97a4e0d18b2ac5d7ceb5c7f077cdcb406aac3496
[openafs.git] / src / WINNT / afsd / cm_vnodeops.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 <windows.h>
14 #include <winsock2.h>
15 #include <stddef.h>
16 #include <malloc.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <errno.h>
20
21 #include <osi.h>
22
23 #include "afsd.h"
24
25 /* Used by cm_FollowMountPoint */
26 #define RWVOL   0
27 #define ROVOL   1
28 #define BACKVOL 2
29
30 #ifdef DEBUG
31 extern void afsi_log(char *pattern, ...);
32 #endif
33
34 int cm_enableServerLocks = 1;
35
36 /*
37  * Case-folding array.  This was constructed by inspecting of SMBtrace output.
38  * I do not know anything more about it.
39  */
40 unsigned char cm_foldUpper[256] = {
41      0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,
42      0x8,  0x9,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
43     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
44     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
45     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
46     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
47     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
48     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
49     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
50     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
51     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
52     0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
53     0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
54     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
55     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
56     0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
57     0x80, 0x9a, 0x90, 0x41, 0x8e, 0x41, 0x8f, 0x80,
58     0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x8e, 0x8f,
59     0x90, 0x92, 0x92, 0x4f, 0x99, 0x4f, 0x55, 0x55,
60     0x59, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
61     0x41, 0x49, 0x4f, 0x55, 0xa5, 0xa5, 0x56, 0xa7,
62     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
63     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
64     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
65     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
66     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
67     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
68     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
69     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
70     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
71     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
72     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
73 };
74
75 /*
76  * Case-insensitive string comparison.  We used to use stricmp, but it doesn't
77  * know about 8-bit characters (e.g. 129 is lowercase u-umlaut, 154 is
78  * upper-case u-umlaut).
79  */
80 int cm_stricmp(const char *str1, const char *str2)
81 {
82     char c1, c2;
83
84     while (1) {
85         if (*str1 == 0)
86             if (*str2 == 0)
87                 return 0;
88             else
89                 return -1;
90         if (*str2 == 0)
91             return 1;
92         c1 = (char) cm_foldUpper[(unsigned char)(*str1++)];
93         c2 = (char) cm_foldUpper[(unsigned char)(*str2++)];
94         if (c1 < c2)
95             return -1;
96         if (c1 > c2)
97             return 1;
98     }
99 }
100
101 /* characters that are legal in an 8.3 name */
102 /*
103  * We used to have 1's for all characters from 128 to 254.  But
104  * the NT client behaves better if we create an 8.3 name for any
105  * name that has a character with the high bit on, and if we
106  * delete those characters from 8.3 names.  In particular, see
107  * Sybase defect 10859.
108  */
109 char cm_LegalChars[256] = {
110  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
113  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
114  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
115  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
116  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
117  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
118  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
126 };
127
128 /* return true iff component is a valid 8.3 name */
129 int cm_Is8Dot3(char *namep)
130 {
131     int sawDot = 0;
132     unsigned char tc;
133     int charCount = 0;
134         
135     /*
136      * can't have a leading dot;
137      * special case for . and ..
138      */
139     if (namep[0] == '.') {
140         if (namep[1] == 0)
141             return 1;
142         if (namep[1] == '.' && namep[2] == 0)
143             return 1;
144         return 0;
145     }
146     while (tc = *namep++) {
147         if (tc == '.') {
148             /* saw another dot */
149             if (sawDot) return 0;       /* second dot */
150             sawDot = 1;
151             charCount = 0;
152             continue;
153         }
154         if (cm_LegalChars[tc] == 0)
155             return 0;
156         charCount++;
157         if (!sawDot && charCount > 8)
158             /* more than 8 chars in name */
159             return 0;
160         if (sawDot && charCount > 3)
161             /* more than 3 chars in extension */
162             return 0;
163     }
164     return 1;
165 }
166
167 /*
168  * Number unparsing map for generating 8.3 names;
169  * The version taken from DFS was on drugs.  
170  * You can't include '&' and '@' in a file name.
171  */
172 char cm_8Dot3Mapping[42] =
173 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
174  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
175  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
176  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '+', '='
177 };
178 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
179
180 void cm_Gen8Dot3NameInt(const char * longname, cm_dirFid_t * pfid,
181                         char *shortName, char **shortNameEndp)
182 {
183     char number[12];
184     int i, nsize = 0;
185     int vnode = ntohl(pfid->vnode);
186     char *lastDot;
187     int validExtension = 0;
188     char tc, *temp, *name;
189
190     /* Unparse the file's vnode number to get a "uniquifier" */
191     do {
192         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
193         nsize++;
194         vnode /= cm_8Dot3MapSize;
195     } while (vnode);
196
197     /*
198      * Look for valid extension.  There has to be a dot, and
199      * at least one of the characters following has to be legal.
200      */
201     lastDot = strrchr(longname, '.');
202     if (lastDot) {
203         temp = lastDot; temp++;
204         while (tc = *temp++)
205             if (cm_LegalChars[tc])
206                 break;
207         if (tc)
208             validExtension = 1;
209     }       
210
211     /* Copy name characters */
212     for (i = 0, name = longname;
213           i < (7 - nsize) && name != lastDot; ) {
214         tc = *name++;
215
216         if (tc == 0)
217             break;
218         if (!cm_LegalChars[tc])
219             continue;
220         i++;
221         *shortName++ = toupper(tc);
222     }
223
224     /* tilde */
225     *shortName++ = '~';
226
227     /* Copy uniquifier characters */
228     memcpy(shortName, number, nsize);
229     shortName += nsize;
230
231     if (validExtension) {
232         /* Copy extension characters */
233         *shortName++ = *lastDot++;      /* copy dot */
234         for (i = 0, tc = *lastDot++;
235               i < 3 && tc;
236               tc = *lastDot++) {
237             if (cm_LegalChars[tc]) {
238                 i++;
239                 *shortName++ = toupper(tc);
240             }
241         }
242     }
243
244     /* Trailing null */
245     *shortName = 0;
246
247     if (shortNameEndp)
248         *shortNameEndp = shortName;
249 }       
250
251 /* return success if we can open this file in this mode */
252 long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
253                   cm_req_t *reqp)
254 {
255     long rights;
256     long code;
257
258     rights = 0;
259     if (openMode != 1) rights |= PRSFS_READ;
260     if (openMode == 1 || openMode == 2 || trunc) rights |= PRSFS_WRITE;
261         
262     lock_ObtainMutex(&scp->mx);
263
264     code = cm_SyncOp(scp, NULL, userp, reqp, rights,
265                       CM_SCACHESYNC_GETSTATUS
266                      | CM_SCACHESYNC_NEEDCALLBACK
267                      | CM_SCACHESYNC_LOCK);
268
269     if (code == 0 && 
270         ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
271         scp->fileType == CM_SCACHETYPE_FILE) {
272
273         cm_key_t key;
274         unsigned int sLockType;
275         LARGE_INTEGER LOffset, LLength;
276
277         /* Check if there's some sort of lock on the file at the
278            moment. */
279
280         key = cm_GenerateKey(CM_SESSION_CMINT,0,0);
281
282         if (rights & PRSFS_WRITE)
283             sLockType = 0;
284         else
285             sLockType = LOCKING_ANDX_SHARED_LOCK;
286
287         LOffset.HighPart = CM_FLSHARE_OFFSET_HIGH;
288         LOffset.LowPart  = CM_FLSHARE_OFFSET_LOW;
289         LLength.HighPart = CM_FLSHARE_LENGTH_HIGH;
290         LLength.LowPart  = CM_FLSHARE_LENGTH_LOW;
291
292         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
293
294         if (code == 0) {
295             cm_Unlock(scp, sLockType, LOffset, LLength, key, userp, reqp);
296         } else {
297             /* In this case, we allow the file open to go through even
298                though we can't enforce mandatory locking on the
299                file. */
300             if (code == CM_ERROR_NOACCESS &&
301                 !(rights & PRSFS_WRITE))
302                 code = 0;
303             else {
304                 switch (code) {
305                 case CM_ERROR_ALLOFFLINE:
306                 case CM_ERROR_ALLDOWN:
307                 case CM_ERROR_ALLBUSY:
308                 case CM_ERROR_TIMEDOUT:
309                 case CM_ERROR_RETRY:
310                 case CM_ERROR_WOULDBLOCK:
311                     break;
312                 default:
313                     code = CM_ERROR_SHARING_VIOLATION;
314                 }
315             }
316         }
317
318     } else if (code != 0) {
319         goto _done;
320     }
321
322     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
323
324  _done:
325
326     lock_ReleaseMutex(&scp->mx);
327
328     return code;
329 }
330
331 /* return success if we can open this file in this mode */
332 long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
333                     unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp, 
334                     cm_lock_data_t **ldpp)
335 {
336     long rights;
337     long code;
338
339     osi_assert(ldpp != NULL);
340     *ldpp = NULL;
341
342     /* Always allow delete; the RPC will tell us if it's OK */
343     if (desiredAccess == DELETE)
344         return 0;
345
346     rights = 0;
347
348     if (desiredAccess & AFS_ACCESS_READ)
349         rights |= PRSFS_READ;
350
351     if ((desiredAccess & AFS_ACCESS_WRITE)
352          || createDisp == 4)
353         rights |= PRSFS_WRITE;
354
355     lock_ObtainMutex(&scp->mx);
356
357     code = cm_SyncOp(scp, NULL, userp, reqp, rights,
358                       CM_SCACHESYNC_GETSTATUS
359                      | CM_SCACHESYNC_NEEDCALLBACK
360                      | CM_SCACHESYNC_LOCK);
361
362     /*
363      * If the open will fail because the volume is readonly, then we will
364      * return an access denied error instead.  This is to help brain-dead
365      * apps run correctly on replicated volumes.
366      * See defect 10007 for more information.
367      */
368     if (code == CM_ERROR_READONLY)
369         code = CM_ERROR_NOACCESS;
370
371     if (code == 0 &&
372              ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
373              scp->fileType == CM_SCACHETYPE_FILE) {
374         cm_key_t key;
375         unsigned int sLockType;
376         LARGE_INTEGER LOffset, LLength;
377
378         /* Check if there's some sort of lock on the file at the
379            moment. */
380
381         key = cm_GenerateKey(CM_SESSION_CMINT,0,0);
382         if (rights & PRSFS_WRITE)
383             sLockType = 0;
384         else
385             sLockType = LOCKING_ANDX_SHARED_LOCK;
386
387         /* single byte lock at offset 0x0100 0000 0000 0000 */
388         LOffset.HighPart = CM_FLSHARE_OFFSET_HIGH;
389         LOffset.LowPart  = CM_FLSHARE_OFFSET_LOW;
390         LLength.HighPart = CM_FLSHARE_LENGTH_HIGH;
391         LLength.LowPart  = CM_FLSHARE_LENGTH_LOW;
392
393         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
394
395         if (code == 0) {
396             (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
397             if (!*ldpp) {
398                 code = ENOMEM;
399                 goto _done;
400             }
401
402             (*ldpp)->key = key;
403             (*ldpp)->sLockType = sLockType;
404             (*ldpp)->LOffset.HighPart = LOffset.HighPart;
405             (*ldpp)->LOffset.LowPart = LOffset.LowPart;
406             (*ldpp)->LLength.HighPart = LLength.HighPart;
407             (*ldpp)->LLength.LowPart = LLength.LowPart;
408         } else {
409             /* In this case, we allow the file open to go through even
410                though we can't enforce mandatory locking on the
411                file. */
412             if (code == CM_ERROR_NOACCESS &&
413                 !(rights & PRSFS_WRITE))
414                 code = 0;
415             else {
416                 switch (code) {
417                 case CM_ERROR_ALLOFFLINE:
418                 case CM_ERROR_ALLDOWN:
419                 case CM_ERROR_ALLBUSY:
420                 case CM_ERROR_TIMEDOUT:
421                 case CM_ERROR_RETRY:
422                 case CM_ERROR_WOULDBLOCK:
423                     break;
424                 default:
425                     code = CM_ERROR_SHARING_VIOLATION;
426                 }
427             }
428         }
429     } else if (code != 0) {
430         goto _done;
431     }
432
433     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
434
435  _done:
436     lock_ReleaseMutex(&scp->mx);
437
438     return code;
439 }
440
441 extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp, 
442                                cm_lock_data_t ** ldpp)
443 {
444     if (*ldpp) {
445         lock_ObtainMutex(&scp->mx);
446         cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength, 
447                   (*ldpp)->key, userp, reqp);
448         lock_ReleaseMutex(&scp->mx);
449         free(*ldpp);
450         *ldpp = NULL;
451     }
452     return 0;
453 }
454 /*
455  * When CAP_NT_SMBS has been negotiated, deletion (of files or directories) is
456  * done in three steps:
457  * (1) open for deletion (NT_CREATE_AND_X)
458  * (2) set for deletion on close (NT_TRANSACTION2, SET_FILE_INFO)
459  * (3) close (CLOSE)
460  * We must not do the RPC until step 3.  But if we are going to return an error
461  * code (e.g. directory not empty), we must return it by step 2, otherwise most
462  * clients will not notice it.  So we do a preliminary check.  For deleting
463  * files, this is almost free, since we have already done the RPC to get the
464  * parent directory's status bits.  But for deleting directories, we must do an
465  * additional RPC to get the directory's data to check if it is empty.  Sigh.
466  */
467 long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
468         cm_req_t *reqp)
469 {
470     long code;
471     osi_hyper_t thyper;
472     cm_buf_t *bufferp;
473     cm_dirEntry_t *dep;
474     unsigned short *hashTable;
475     unsigned int i, idx;
476     int BeyondPage = 0, HaveDot = 0, HaveDotDot = 0;
477
478     /* First check permissions */
479     lock_ObtainMutex(&dscp->mx);
480     code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_DELETE,
481                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
482     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
483     lock_ReleaseMutex(&dscp->mx);
484     if (code)
485         return code;
486
487     /* If deleting directory, must be empty */
488
489     if (scp->fileType != CM_SCACHETYPE_DIRECTORY)
490         return code;
491
492     thyper.HighPart = 0; thyper.LowPart = 0;
493     lock_ObtainRead(&scp->bufCreateLock);
494     code = buf_Get(scp, &thyper, &bufferp);
495     lock_ReleaseRead(&scp->bufCreateLock);
496     if (code)
497         return code;
498
499     lock_ObtainMutex(&bufferp->mx);
500     lock_ObtainMutex(&scp->mx);
501     while (1) {
502         code = cm_SyncOp(scp, bufferp, userp, reqp, 0,
503                           CM_SCACHESYNC_NEEDCALLBACK
504                           | CM_SCACHESYNC_READ
505                           | CM_SCACHESYNC_BUFLOCKED);
506         if (code)
507             break;
508
509         if (cm_HaveBuffer(scp, bufferp, 1))
510             break;
511
512         /* otherwise, load the buffer and try again */
513         lock_ReleaseMutex(&bufferp->mx);
514         code = cm_GetBuffer(scp, bufferp, NULL, userp, reqp);
515         lock_ReleaseMutex(&scp->mx);
516         lock_ObtainMutex(&bufferp->mx);
517         lock_ObtainMutex(&scp->mx);
518         cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
519         if (code)
520             break;
521     }
522
523     /* We try to determine emptiness without looking beyond the first page,
524      * and without assuming "." and ".." are present and are on the first
525      * page (though these assumptions might, after all, be reasonable).
526      */
527     hashTable = (unsigned short *)(bufferp->datap + (32 * 5));
528     for (i=0; i<128; i++) {
529         idx = ntohs(hashTable[i]);
530         while (idx) {
531             if (idx >= 64) {
532                 BeyondPage = 1;
533                 break;
534             }
535             dep = (cm_dirEntry_t *)(bufferp->datap + (32 * idx));
536             if (strcmp(dep->name, ".") == 0)
537                 HaveDot = 1;
538             else if (strcmp(dep->name, "..") == 0)
539                 HaveDotDot = 1;
540             else {
541                 code = CM_ERROR_NOTEMPTY;
542                 goto done;
543             }
544             idx = ntohs(dep->next);
545         }
546     }
547     if (BeyondPage && HaveDot && HaveDotDot)
548         code = CM_ERROR_NOTEMPTY;
549     else
550         code = 0;
551   done:   
552     lock_ReleaseMutex(&bufferp->mx);
553     buf_Release(bufferp);
554     lock_ReleaseMutex(&scp->mx);
555     return code;
556 }       
557
558 /*
559  * Iterate through all entries in a directory.
560  * When the function funcp is called, the buffer is locked but the
561  * directory vnode is not.
562  *
563  * If the retscp parameter is not NULL, the parmp must be a 
564  * cm_lookupSearch_t object.  
565  */
566 long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
567                   osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
568                   cm_scache_t **retscp)
569 {
570     char *tp;
571     long code;
572     cm_dirEntry_t *dep;
573     cm_buf_t *bufferp;
574     long temp;
575     osi_hyper_t dirLength;
576     osi_hyper_t bufferOffset;
577     osi_hyper_t curOffset;
578     osi_hyper_t thyper;
579     long entryInDir;
580     long entryInBuffer;
581     cm_pageHeader_t *pageHeaderp;
582     int slotInPage;
583     long nextEntryCookie;
584     int numDirChunks;   /* # of 32 byte dir chunks in this entry */
585         
586     /* get the directory size */
587     lock_ObtainMutex(&scp->mx);
588     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
589                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
590     if (code) {
591         lock_ReleaseMutex(&scp->mx);
592         return code;
593     }
594         
595     if (scp->fileType != CM_SCACHETYPE_DIRECTORY) {
596         lock_ReleaseMutex(&scp->mx);
597         return CM_ERROR_NOTDIR;
598     }   
599
600     if (retscp)                         /* if this is a lookup call */
601     {
602         cm_lookupSearch_t*      sp = parmp;
603
604 #ifdef AFS_FREELANCE_CLIENT
605         /* Freelance entries never end up in the DNLC because they
606          * do not have an associated cm_server_t
607          */
608     if ( !(cm_freelanceEnabled &&
609             sp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
610             sp->fid.volume==AFS_FAKE_ROOT_VOL_ID ) )
611 #endif /* AFS_FREELANCE_CLIENT */
612     {
613         int casefold = sp->caseFold;
614         sp->caseFold = 0; /* we have a strong preference for exact matches */
615         if ( *retscp = cm_dnlcLookup(scp, sp))  /* dnlc hit */
616         {
617             sp->caseFold = casefold;
618             lock_ReleaseMutex(&scp->mx);
619             return 0;
620         }
621         sp->caseFold = casefold;
622     }
623     }   
624
625     /*
626      * XXX We only get the length once.  It might change when we drop the
627      * lock.
628      */
629     dirLength = scp->length;
630
631     lock_ReleaseMutex(&scp->mx);
632
633     bufferp = NULL;
634     bufferOffset.LowPart = bufferOffset.HighPart = 0;
635     if (startOffsetp)
636         curOffset = *startOffsetp;
637     else {
638         curOffset.HighPart = 0;
639         curOffset.LowPart = 0;
640     }   
641
642     while (1) {
643         /* make sure that curOffset.LowPart doesn't point to the first
644          * 32 bytes in the 2nd through last dir page, and that it
645          * doesn't point at the first 13 32-byte chunks in the first
646          * dir page, since those are dir and page headers, and don't
647          * contain useful information.
648          */
649         temp = curOffset.LowPart & (2048-1);
650         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
651             /* we're in the first page */
652             if (temp < 13*32) temp = 13*32;
653         }
654         else {
655             /* we're in a later dir page */
656             if (temp < 32) temp = 32;
657         }       
658                 
659         /* make sure the low order 5 bits are zero */
660         temp &= ~(32-1);
661                 
662         /* now put temp bits back ito curOffset.LowPart */
663         curOffset.LowPart &= ~(2048-1);
664         curOffset.LowPart |= temp;
665
666         /* check if we've passed the dir's EOF */
667         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength))
668             break;
669                 
670         /* see if we can use the bufferp we have now; compute in which
671          * page the current offset would be, and check whether that's
672          * the offset of the buffer we have.  If not, get the buffer.
673          */
674         thyper.HighPart = curOffset.HighPart;
675         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
676         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
677             /* wrong buffer */
678             if (bufferp) {
679                 lock_ReleaseMutex(&bufferp->mx);
680                 buf_Release(bufferp);
681                 bufferp = NULL;
682             }
683
684             lock_ObtainRead(&scp->bufCreateLock);
685             code = buf_Get(scp, &thyper, &bufferp);
686             lock_ReleaseRead(&scp->bufCreateLock);
687             if (code) {
688                 /* if buf_Get() fails we do not have a buffer object to lock */
689                 bufferp = NULL;
690                 break;
691             }
692
693 #ifdef AFSIFS
694             /* for the IFS version, we bulkstat the dirents because this
695                routine is used in place of smb_ReceiveCoreSearchDir.  our
696                other option is to modify smb_ReceiveCoreSearchDir itself, 
697                but this seems to be the proper use for cm_ApplyDir. */
698             lock_ObtainMutex(&scp->mx);
699             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
700                  && (scp->bulkStatProgress.QuadPart <= thyper.QuadPart))
701             {
702                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
703                 code = cm_TryBulkStat(scp, &thyper, userp, reqp);
704                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
705                 scp->bulkStatProgress = thyper;
706             }
707             lock_ReleaseMutex(&scp->mx);
708 #endif
709
710             lock_ObtainMutex(&bufferp->mx);
711             bufferOffset = thyper;
712
713             /* now get the data in the cache */
714             while (1) {
715                 lock_ObtainMutex(&scp->mx);
716                 code = cm_SyncOp(scp, bufferp, userp, reqp,
717                                   PRSFS_LOOKUP,
718                                   CM_SCACHESYNC_NEEDCALLBACK
719                                   | CM_SCACHESYNC_READ
720                                   | CM_SCACHESYNC_BUFLOCKED);
721                 if (code) {
722                     lock_ReleaseMutex(&scp->mx);
723                     break;
724                 }
725                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
726                                 
727                 if (cm_HaveBuffer(scp, bufferp, 1)) {
728                     lock_ReleaseMutex(&scp->mx);
729                     break;
730                 }
731
732                 /* otherwise, load the buffer and try again */
733                 lock_ReleaseMutex(&bufferp->mx);
734                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
735                                     reqp);
736                 lock_ReleaseMutex(&scp->mx);
737                 lock_ObtainMutex(&bufferp->mx);
738                 if (code) 
739                     break;
740             }
741             if (code) {
742                 lock_ReleaseMutex(&bufferp->mx);
743                 buf_Release(bufferp);
744                 bufferp = NULL;
745                 break;
746             }
747         }       /* if (wrong buffer) ... */
748            
749         /* now we have the buffer containing the entry we're interested
750          * in; copy it out if it represents a non-deleted entry.
751          */
752         entryInDir = curOffset.LowPart & (2048-1);
753         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
754
755         /* page header will help tell us which entries are free.  Page
756          * header can change more often than once per buffer, since
757          * AFS 3 dir page size may be less than (but not more than) a
758          * buffer package buffer.
759          */
760         /* only look intra-buffer */
761         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
762         temp &= ~(2048 - 1);    /* turn off intra-page bits */
763         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
764
765         /* now determine which entry we're looking at in the page.  If
766          * it is free (there's a free bitmap at the start of the dir),
767          * we should skip these 32 bytes.
768          */
769         slotInPage = (entryInDir & 0x7e0) >> 5;
770         if (!(pageHeaderp->freeBitmap[slotInPage>>3]
771                & (1 << (slotInPage & 0x7)))) {
772             /* this entry is free */
773             numDirChunks = 1;   /* only skip this guy */
774             goto nextEntry;
775         }
776
777         tp = bufferp->datap + entryInBuffer;
778         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
779
780         /* while we're here, compute the next entry's location, too,
781          * since we'll need it when writing out the cookie into the
782          * dir listing stream.
783          */
784         numDirChunks = cm_NameEntries(dep->name, NULL);
785                 
786         /* compute the offset of the cookie representing the next entry */
787         nextEntryCookie = curOffset.LowPart
788             + (CM_DIR_CHUNKSIZE * numDirChunks);
789
790         if (dep->fid.vnode != 0) {
791             /* this is one of the entries to use: it is not deleted */
792             code = (*funcp)(scp, dep, parmp, &curOffset);
793             if (code) 
794                 break;
795         }       /* if we're including this name */
796                 
797       nextEntry:
798         /* and adjust curOffset to be where the new cookie is */
799         thyper.HighPart = 0;
800         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
801         curOffset = LargeIntegerAdd(thyper, curOffset);
802     }           /* while copying data for dir listing */
803
804     /* release the mutex */
805     if (bufferp) {
806         lock_ReleaseMutex(&bufferp->mx);
807         buf_Release(bufferp);
808     }
809     return code;
810 }
811
812 int cm_NoneUpper(char *s)
813 {
814     char c;
815     while (c = *s++)
816         if (c >= 'A' && c <= 'Z')
817             return 0;
818     return 1;
819 }
820
821 int cm_NoneLower(char *s)
822 {
823     char c;
824     while (c = *s++)
825         if (c >= 'a' && c <= 'z')
826             return 0;
827     return 1;
828 }
829
830 long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
831                           osi_hyper_t *offp)
832 {
833     cm_lookupSearch_t *sp;
834     int match;
835     char shortName[13];
836     char *matchName;
837
838     sp = (cm_lookupSearch_t *) rockp;
839
840     matchName = dep->name;
841     if (sp->caseFold)
842         match = cm_stricmp(matchName, sp->searchNamep);
843     else
844         match = strcmp(matchName, sp->searchNamep);
845
846     if (match != 0
847          && sp->hasTilde
848          && !cm_Is8Dot3(dep->name)) {
849         matchName = shortName;
850         cm_Gen8Dot3Name(dep, shortName, NULL);
851         if (sp->caseFold)
852             match = cm_stricmp(matchName, sp->searchNamep);
853         else
854             match = strcmp(matchName, sp->searchNamep);
855     }
856
857     if (match != 0)
858         return 0;
859
860     sp->found = 1;
861     if (!sp->caseFold) 
862         sp->ExactFound = 1;
863
864     if (!sp->caseFold || matchName == shortName) {
865         sp->fid.vnode = ntohl(dep->fid.vnode);
866         sp->fid.unique = ntohl(dep->fid.unique);
867         return CM_ERROR_STOPNOW;
868     }
869
870     /*
871      * If we get here, we are doing a case-insensitive search, and we
872      * have found a match.  Now we determine what kind of match it is:
873      * exact, lower-case, upper-case, or none of the above.  This is done
874      * in order to choose among matches, if there are more than one.
875      */
876
877     /* Exact matches are the best. */
878     match = strcmp(matchName, sp->searchNamep);
879     if (match == 0) {
880         sp->ExactFound = 1;
881         sp->fid.vnode = ntohl(dep->fid.vnode);
882         sp->fid.unique = ntohl(dep->fid.unique);
883         return CM_ERROR_STOPNOW;
884     }
885
886     /* Lower-case matches are next. */
887     if (sp->LCfound)
888         return 0;
889     if (cm_NoneUpper(matchName)) {
890         sp->LCfound = 1;
891         goto inexact;
892     }
893
894     /* Upper-case matches are next. */
895     if (sp->UCfound)
896         return 0;
897     if (cm_NoneLower(matchName)) {
898         sp->UCfound = 1;
899         goto inexact;
900     }
901
902     /* General matches are last. */
903     if (sp->NCfound)
904         return 0;
905     sp->NCfound = 1;
906
907   inexact:
908     sp->fid.vnode = ntohl(dep->fid.vnode);
909     sp->fid.unique = ntohl(dep->fid.unique);
910     return 0;
911 }       
912
913 /* read the contents of a mount point into the appropriate string.
914  * called with locked scp, and returns with locked scp.
915  */
916 long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
917 {
918     long code;
919     cm_buf_t *bufp;
920     osi_hyper_t thyper;
921     int tlen;
922
923     if (scp->mountPointStringp[0]) 
924         return 0;
925         
926     /* otherwise, we have to read it in */
927     lock_ReleaseMutex(&scp->mx);
928
929     lock_ObtainRead(&scp->bufCreateLock);
930     thyper.LowPart = thyper.HighPart = 0;
931     code = buf_Get(scp, &thyper, &bufp);
932     lock_ReleaseRead(&scp->bufCreateLock);
933
934     lock_ObtainMutex(&scp->mx);
935     if (code) {
936         return code;
937     }
938     while (1) {
939         code = cm_SyncOp(scp, bufp, userp, reqp, 0,
940                           CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
941         if (code) {
942             goto done;
943         }
944         cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
945
946
947         if (cm_HaveBuffer(scp, bufp, 0)) 
948             break;
949
950         /* otherwise load buffer */
951         code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
952         if (code) {
953             goto done;
954         }
955     }
956     /* locked, has callback, has valid data in buffer */
957     if ((tlen = scp->length.LowPart) > 1000) 
958         return CM_ERROR_TOOBIG;
959     if (tlen <= 0) {
960         code = CM_ERROR_INVAL;
961         goto done;
962     }
963
964     /* someone else did the work while we were out */
965     if (scp->mountPointStringp[0]) {
966         code = 0;
967         goto done;
968     }
969
970     /* otherwise, copy out the link */
971     memcpy(scp->mountPointStringp, bufp->datap, tlen);
972
973     /* now make it null-terminated.  Note that the original contents of a
974      * link that is a mount point is "#volname." where "." is there just to
975      * be turned into a null.  That is, we can trash the last char of the
976      * link without damaging the vol name.  This is a stupid convention,
977      * but that's the protocol.
978      */
979     scp->mountPointStringp[tlen-1] = 0;
980     code = 0;
981
982   done:
983     if (bufp) 
984         buf_Release(bufp);
985     return code;
986 }
987
988 /* called with a locked scp and chases the mount point, yielding outScpp.
989  * scp remains locked, just for simplicity of describing the interface.
990  */
991 long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
992                          cm_req_t *reqp, cm_scache_t **outScpp)
993 {
994     char *cellNamep;
995     char *volNamep;
996     int tlen;
997     long code;
998     char *cp;
999     char *mpNamep;
1000     cm_volume_t *volp;
1001     cm_cell_t *cellp;
1002     char mtType;
1003     cm_fid_t tfid;
1004     size_t vnLength;
1005     int type;
1006
1007     if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
1008         tfid = scp->mountRootFid;
1009         lock_ReleaseMutex(&scp->mx);
1010         code = cm_GetSCache(&tfid, outScpp, userp, reqp);
1011         lock_ObtainMutex(&scp->mx);
1012         return code;
1013     }
1014
1015     /* parse the volume name */
1016     mpNamep = scp->mountPointStringp;
1017     if (!mpNamep[0])
1018         return CM_ERROR_NOSUCHPATH;
1019     tlen = (int)strlen(scp->mountPointStringp);
1020     mtType = *scp->mountPointStringp;
1021     cellNamep = malloc(tlen);
1022     volNamep = malloc(tlen);
1023
1024     cp = strrchr(mpNamep, ':');
1025     if (cp) {
1026         /* cellular mount point */
1027         memset(cellNamep, 0, tlen);
1028         strncpy(cellNamep, mpNamep+1, cp - mpNamep - 1);
1029         strcpy(volNamep, cp+1);
1030         /* now look up the cell */
1031         cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
1032     }
1033     else {
1034         /* normal mt pt */
1035         strcpy(volNamep, mpNamep+1);
1036
1037         cellp = cm_FindCellByID(scp->fid.cell);
1038     }
1039
1040     if (!cellp) {
1041         code = CM_ERROR_NOSUCHCELL;
1042         goto done;
1043     }
1044
1045     vnLength = strlen(volNamep);
1046     if (vnLength >= 8 && strcmp(volNamep + vnLength - 7, ".backup") == 0)
1047         type = BACKVOL;
1048     else if (vnLength >= 10
1049               && strcmp(volNamep + vnLength - 9, ".readonly") == 0)
1050         type = ROVOL;
1051     else
1052         type = RWVOL;
1053
1054     /* check for backups within backups */
1055     if (type == BACKVOL
1056          && (scp->flags & (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
1057          == CM_SCACHEFLAG_RO) {
1058         code = CM_ERROR_NOSUCHVOLUME;
1059         goto done;
1060     }
1061
1062     /* now we need to get the volume */
1063     lock_ReleaseMutex(&scp->mx);
1064     code = cm_GetVolumeByName(cellp, volNamep, userp, reqp, 0, &volp);
1065     lock_ObtainMutex(&scp->mx);
1066         
1067     if (code == 0) {
1068         /* save the parent of the volume root for this is the 
1069          * place where the volume is mounted and we must remember 
1070          * this in the volume structure rather than just in the 
1071          * scache entry lest the scache entry gets recycled 
1072          * (defect 11489)
1073          */
1074         lock_ObtainMutex(&volp->mx);
1075         volp->dotdotFid = dscp->fid;
1076         lock_ReleaseMutex(&volp->mx);
1077
1078         scp->mountRootFid.cell = cellp->cellID;
1079         /* if the mt pt is in a read-only volume (not just a
1080          * backup), and if there is a read-only volume for the
1081          * target, and if this is a type '#' mount point, use
1082          * the read-only, otherwise use the one specified.
1083          */
1084         if (mtType == '#' && (scp->flags & CM_SCACHEFLAG_PURERO)
1085              && volp->roID != 0 && type == RWVOL)
1086             type = ROVOL;
1087         if (type == ROVOL)
1088             scp->mountRootFid.volume = volp->roID;
1089         else if (type == BACKVOL)
1090             scp->mountRootFid.volume = volp->bkID;
1091         else
1092             scp->mountRootFid.volume = volp->rwID;
1093
1094         /* the rest of the fid is a magic number */
1095         scp->mountRootFid.vnode = 1;
1096         scp->mountRootFid.unique = 1;
1097         scp->mountRootGen = cm_data.mountRootGen;
1098
1099         tfid = scp->mountRootFid;
1100         lock_ReleaseMutex(&scp->mx);
1101         code = cm_GetSCache(&tfid, outScpp, userp, reqp);
1102         lock_ObtainMutex(&scp->mx);
1103     }
1104
1105   done:
1106     free(cellNamep);
1107     free(volNamep);
1108     return code;
1109 }       
1110
1111 long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
1112                        cm_req_t *reqp, cm_scache_t **outpScpp)
1113 {
1114     long code;
1115     int dnlcHit = 1;    /* did we hit in the dnlc? yes, we did */
1116     cm_scache_t *tscp = NULL;
1117     cm_scache_t *mountedScp;
1118     cm_lookupSearch_t rock;
1119     int getroot;
1120
1121     if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
1122          && strcmp(namep, "..") == 0) {
1123         if (dscp->dotdotFid.volume == 0)
1124             return CM_ERROR_NOSUCHVOLUME;
1125         rock.fid = dscp->dotdotFid;
1126         goto haveFid;
1127     } else if (strcmp(namep, ".") == 0) {
1128         rock.fid = dscp->fid;
1129         goto haveFid;
1130     }
1131
1132     memset(&rock, 0, sizeof(rock));
1133     rock.fid.cell = dscp->fid.cell;
1134     rock.fid.volume = dscp->fid.volume;
1135     rock.searchNamep = namep;
1136     rock.caseFold = (flags & CM_FLAG_CASEFOLD);
1137     rock.hasTilde = ((strchr(namep, '~') != NULL) ? 1 : 0);
1138
1139     /* If NOMOUNTCHASE, bypass DNLC by passing NULL scp pointer */
1140     code = cm_ApplyDir(dscp, cm_LookupSearchProc, &rock, NULL, userp, reqp,
1141                         (flags & CM_FLAG_NOMOUNTCHASE) ? NULL : &tscp);
1142
1143     /* code == 0 means we fell off the end of the dir, while stopnow means
1144      * that we stopped early, probably because we found the entry we're
1145      * looking for.  Any other non-zero code is an error.
1146      */
1147     if (code && code != CM_ERROR_STOPNOW) {
1148         /* if the cm_scache_t we are searching in is not a directory 
1149          * we must return path not found because the error 
1150          * is to describe the final component not an intermediary
1151          */
1152         if (code == CM_ERROR_NOTDIR) {
1153             if (flags & CM_FLAG_CHECKPATH)
1154                 return CM_ERROR_NOSUCHPATH;
1155             else
1156                 return CM_ERROR_NOSUCHFILE;
1157         }
1158         return code;
1159     }
1160
1161     getroot = (dscp==cm_data.rootSCachep) ;
1162     if (!rock.found) {
1163         if (!cm_freelanceEnabled || !getroot) {
1164             if (flags & CM_FLAG_CHECKPATH)
1165                 return CM_ERROR_NOSUCHPATH;
1166             else
1167                 return CM_ERROR_NOSUCHFILE;
1168         }
1169         else {  /* nonexistent dir on freelance root, so add it */
1170             char fullname[200] = ".";
1171             int  found = 0;
1172
1173             osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s", 
1174                       osi_LogSaveString(afsd_logp,namep));
1175             if (namep[0] == '.') {
1176                 if (cm_GetCell_Gen(&namep[1], &fullname[1], CM_FLAG_CREATE)) {
1177                     found = 1;
1178                     if ( stricmp(&namep[1], &fullname[1]) )
1179                         code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
1180                     else
1181                         code = cm_FreelanceAddMount(namep, &fullname[1], "root.cell.", 1, &rock.fid);
1182                 }
1183             } else {
1184                 if (cm_GetCell_Gen(namep, fullname, CM_FLAG_CREATE)) {
1185                     found = 1;
1186                     if ( stricmp(namep, fullname) )
1187                         code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
1188                     else
1189                         code = cm_FreelanceAddMount(namep, fullname, "root.cell.", 0, &rock.fid);
1190                 }
1191             }
1192             if (!found || code < 0) {   /* add mount point failed, so give up */
1193                 if (flags & CM_FLAG_CHECKPATH)
1194                     return CM_ERROR_NOSUCHPATH;
1195                 else
1196                     return CM_ERROR_NOSUCHFILE;
1197             }
1198             tscp = NULL;   /* to force call of cm_GetSCache */
1199         }
1200     }
1201
1202   haveFid:       
1203     if ( !tscp )    /* we did not find it in the dnlc */
1204     {
1205         dnlcHit = 0;    
1206         code = cm_GetSCache(&rock.fid, &tscp, userp, reqp);
1207         if (code) 
1208             return code;
1209     }       
1210     /* tscp is now held */
1211
1212     lock_ObtainMutex(&tscp->mx);
1213     code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
1214                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1215     if (code) { 
1216         lock_ReleaseMutex(&tscp->mx);
1217         cm_ReleaseSCache(tscp);
1218         return code;
1219     }
1220     cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1221     /* tscp is now locked */
1222
1223     if (!(flags & CM_FLAG_NOMOUNTCHASE)
1224          && tscp->fileType == CM_SCACHETYPE_MOUNTPOINT) {
1225         /* mount points are funny: they have a volume name to mount
1226          * the root of.
1227          */
1228         code = cm_ReadMountPoint(tscp, userp, reqp);
1229         if (code == 0)
1230             code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
1231                                         &mountedScp);
1232         lock_ReleaseMutex(&tscp->mx);
1233         cm_ReleaseSCache(tscp);
1234         if (code) {
1235             return code;
1236         }
1237         tscp = mountedScp;
1238     }
1239     else {
1240         lock_ReleaseMutex(&tscp->mx);
1241     }
1242
1243     /* copy back pointer */
1244     *outpScpp = tscp;
1245
1246     /* insert scache in dnlc */
1247     if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
1248         /* lock the directory entry to prevent racing callback revokes */
1249         lock_ObtainMutex(&dscp->mx);
1250         if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 )
1251             cm_dnlcEnter(dscp, namep, tscp);
1252         lock_ReleaseMutex(&dscp->mx);
1253     }
1254
1255     /* and return */
1256     return 0;
1257 }
1258
1259 int cm_ExpandSysName(char *inp, char *outp, long outSize, unsigned int index)
1260 {
1261     char *tp;
1262     int prefixCount;
1263
1264     tp = strrchr(inp, '@');
1265     if (tp == NULL) 
1266         return 0;               /* no @sys */
1267
1268     if (strcmp(tp, "@sys") != 0) 
1269         return 0;       /* no @sys */
1270
1271     /* caller just wants to know if this is a valid @sys type of name */
1272     if (outp == NULL) 
1273         return 1;
1274
1275     if (index >= MAXNUMSYSNAMES)
1276         return -1;
1277
1278     /* otherwise generate the properly expanded @sys name */
1279     prefixCount = (int)(tp - inp);
1280
1281     strncpy(outp, inp, prefixCount);    /* copy out "a." from "a.@sys" */
1282     outp[prefixCount] = 0;              /* null terminate the "a." */
1283     strcat(outp, cm_sysNameList[index]);/* append i386_nt40 */
1284     return 1;
1285 }   
1286
1287 #ifdef DEBUG_REFCOUNT
1288 long cm_LookupDbg(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
1289                cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
1290 #else
1291 long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
1292                cm_req_t *reqp, cm_scache_t **outpScpp)
1293 #endif
1294 {
1295     long code;
1296     char tname[256];
1297     int sysNameIndex = 0;
1298     cm_scache_t *scp = NULL;
1299
1300 #ifdef DEBUG_REFCOUNT
1301     afsi_log("%s:%d cm_Lookup dscp 0x%p ref %d", file, line, dscp, dscp->refCount, file, line);
1302     osi_Log2(afsd_logp, "cm_Lookup dscp 0x%p ref %d", dscp, dscp->refCount);
1303 #endif
1304
1305     if ( stricmp(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
1306         if (flags & CM_FLAG_CHECKPATH)
1307             return CM_ERROR_NOSUCHPATH;
1308         else
1309             return CM_ERROR_NOSUCHFILE;
1310     }
1311
1312     for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
1313         code = cm_ExpandSysName(namep, tname, sizeof(tname), sysNameIndex);
1314         if (code > 0) {
1315             code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
1316 #ifdef DEBUG_REFCOUNT
1317             afsi_log("%s:%d cm_LookupInternal (1) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
1318             osi_Log3(afsd_logp, "cm_LookupInternal (1) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
1319 #endif
1320
1321             if (code == 0) {
1322                 *outpScpp = scp;
1323                 return 0;
1324             }
1325             if (scp) {
1326                 cm_ReleaseSCache(scp);
1327                 scp = NULL;
1328             }
1329         } else {
1330             code = cm_LookupInternal(dscp, namep, flags, userp, reqp, &scp);
1331 #ifdef DEBUG_REFCOUNT
1332             afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
1333             osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
1334 #endif
1335             *outpScpp = scp;
1336             return code;
1337         }
1338     }
1339
1340     /* None of the possible sysName expansions could be found */
1341     if (flags & CM_FLAG_CHECKPATH)
1342         return CM_ERROR_NOSUCHPATH;
1343     else
1344         return CM_ERROR_NOSUCHFILE;
1345 }
1346
1347 long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
1348 {
1349     long code;
1350     cm_conn_t *connp;
1351     AFSFid afsFid;
1352     int sflags;
1353     AFSFetchStatus newDirStatus;
1354     AFSVolSync volSync;
1355     struct rx_connection * callp;
1356
1357 #ifdef AFS_FREELANCE_CLIENT
1358     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1359         /* deleting a mount point from the root dir. */
1360         code = cm_FreelanceRemoveMount(namep);
1361         return code;
1362     }
1363 #endif  
1364
1365     /* make sure we don't screw up the dir status during the merge */
1366     lock_ObtainMutex(&dscp->mx);
1367     sflags = CM_SCACHESYNC_STOREDATA;
1368     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags);
1369     lock_ReleaseMutex(&dscp->mx);
1370     if (code) 
1371         return code;
1372
1373     /* make the RPC */
1374     afsFid.Volume = dscp->fid.volume;
1375     afsFid.Vnode = dscp->fid.vnode;
1376     afsFid.Unique = dscp->fid.unique;
1377
1378     osi_Log1(afsd_logp, "CALL RemoveFile scp 0x%p", dscp);
1379     do {
1380         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
1381         if (code) 
1382             continue;
1383
1384         callp = cm_GetRxConn(connp);
1385         code = RXAFS_RemoveFile(callp, &afsFid, namep,
1386                                  &newDirStatus, &volSync);
1387         rx_PutConnection(callp);
1388
1389     } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
1390     code = cm_MapRPCError(code, reqp);
1391
1392     if (code)
1393         osi_Log1(afsd_logp, "CALL RemoveFile FAILURE, code 0x%x", code);
1394     else
1395         osi_Log0(afsd_logp, "CALL RemoveFile SUCCESS");
1396
1397     lock_ObtainMutex(&dscp->mx);
1398     cm_dnlcRemove(dscp, namep);
1399     cm_SyncOpDone(dscp, NULL, sflags);
1400     if (code == 0) 
1401         cm_MergeStatus(dscp, &newDirStatus, &volSync, userp, 0);
1402         else if (code == CM_ERROR_NOSUCHFILE) {
1403                 /* windows would not have allowed the request to delete the file 
1404                  * if it did not believe the file existed.  therefore, we must 
1405                  * have an inconsistent view of the world.
1406                  */
1407                 dscp->cbServerp = NULL;
1408         }
1409     lock_ReleaseMutex(&dscp->mx);
1410
1411     return code;
1412 }
1413
1414 /* called with a locked vnode, and fills in the link info.
1415  * returns this the vnode still locked.
1416  */
1417 long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
1418 {
1419     long code;
1420     cm_buf_t *bufp;
1421     long temp;
1422     osi_hyper_t thyper;
1423
1424     lock_AssertMutex(&linkScp->mx);
1425     if (!linkScp->mountPointStringp[0]) {
1426         /* read the link data */
1427         lock_ReleaseMutex(&linkScp->mx);
1428         thyper.LowPart = thyper.HighPart = 0;
1429         code = buf_Get(linkScp, &thyper, &bufp);
1430         lock_ObtainMutex(&linkScp->mx);
1431         if (code) 
1432             return code;
1433         while (1) {
1434             code = cm_SyncOp(linkScp, bufp, userp, reqp, 0,
1435                               CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
1436             if (code) {
1437                 buf_Release(bufp);
1438                 return code;
1439             }
1440             cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
1441
1442             if (cm_HaveBuffer(linkScp, bufp, 0)) 
1443                 break;
1444
1445             code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
1446             if (code) {
1447                 buf_Release(bufp);
1448                 return code;
1449             }
1450         } /* while loop to get the data */
1451                 
1452         /* now if we still have no link read in,
1453          * copy the data from the buffer */
1454         if ((temp = linkScp->length.LowPart) >= MOUNTPOINTLEN) {
1455             buf_Release(bufp);
1456             return CM_ERROR_TOOBIG;
1457         }
1458
1459         /* otherwise, it fits; make sure it is still null (could have
1460          * lost race with someone else referencing this link above),
1461          * and if so, copy in the data.
1462          */
1463         if (!linkScp->mountPointStringp[0]) {
1464             strncpy(linkScp->mountPointStringp, bufp->datap, temp);
1465             linkScp->mountPointStringp[temp] = 0;       /* null terminate */
1466         }
1467         buf_Release(bufp);
1468     }   /* don't have sym link contents cached */
1469
1470     return 0;
1471 }       
1472
1473 /* called with a held vnode and a path suffix, with the held vnode being a
1474  * symbolic link.  Our goal is to generate a new path to interpret, and return
1475  * this new path in newSpaceBufferp.  If the new vnode is relative to a dir
1476  * other than the directory containing the symbolic link, then the new root is
1477  * returned in *newRootScpp, otherwise a null is returned there.
1478  */
1479 long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
1480                       cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
1481                       cm_user_t *userp, cm_req_t *reqp)
1482 {
1483     long code = 0;
1484     long len;
1485     char *linkp;
1486     cm_space_t *tsp;
1487
1488     lock_ObtainMutex(&linkScp->mx);
1489     code = cm_HandleLink(linkScp, userp, reqp);
1490     if (code) 
1491         goto done;
1492
1493     /* if we may overflow the buffer, bail out; buffer is signficantly
1494      * bigger than max path length, so we don't really have to worry about
1495      * being a little conservative here.
1496      */
1497     if (strlen(linkScp->mountPointStringp) + strlen(pathSuffixp) + 2
1498          >= CM_UTILS_SPACESIZE)
1499         return CM_ERROR_TOOBIG;
1500
1501     tsp = cm_GetSpace();
1502     linkp = linkScp->mountPointStringp;
1503     if (strncmp(linkp, cm_mountRoot, cm_mountRootLen) == 0) {
1504         if (strlen(linkp) > cm_mountRootLen)
1505             strcpy(tsp->data, linkp+cm_mountRootLen+1);
1506         else
1507             tsp->data[0] = 0;
1508         *newRootScpp = cm_data.rootSCachep;
1509         cm_HoldSCache(cm_data.rootSCachep);
1510     } else if (linkp[0] == '\\' && linkp[1] == '\\') {
1511         if (!strnicmp(&linkp[2], cm_NetbiosName, (len = (long)strlen(cm_NetbiosName)))) 
1512         {
1513             char * p = &linkp[len + 3];
1514             if (strnicmp(p, "all", 3) == 0)
1515                 p += 4;
1516
1517             strcpy(tsp->data, p);
1518             for (p = tsp->data; *p; p++) {
1519                 if (*p == '\\')
1520                     *p = '/';
1521             }
1522             *newRootScpp = cm_data.rootSCachep;
1523             cm_HoldSCache(cm_data.rootSCachep);
1524         } else {
1525             linkScp->fileType = CM_SCACHETYPE_DFSLINK;
1526             strcpy(tsp->data, linkp);
1527             *newRootScpp = NULL;
1528             code = CM_ERROR_PATH_NOT_COVERED;
1529         }
1530     } else if ( !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
1531         linkScp->fileType = CM_SCACHETYPE_DFSLINK;
1532         strcpy(tsp->data, linkp);
1533         *newRootScpp = NULL;
1534         code = CM_ERROR_PATH_NOT_COVERED;
1535     } else if (*linkp == '\\' || *linkp == '/') {
1536 #if 0   
1537         /* formerly, this was considered to be from the AFS root,
1538          * but this seems to create problems.  instead, we will just
1539          * reject the link */
1540         strcpy(tsp->data, linkp+1);
1541         *newRootScpp = cm_data.rootSCachep;
1542         cm_HoldSCache(cm_data.rootSCachep);
1543 #else
1544         /* we still copy the link data into the response so that 
1545          * the user can see what the link points to
1546          */
1547         linkScp->fileType = CM_SCACHETYPE_INVALID;
1548         strcpy(tsp->data, linkp);
1549         *newRootScpp = NULL;
1550         code = CM_ERROR_NOSUCHPATH;
1551 #endif  
1552     } else {
1553         /* a relative link */
1554         strcpy(tsp->data, linkp);
1555         *newRootScpp = NULL;
1556     }
1557     if (pathSuffixp[0] != 0) {  /* if suffix string is non-null */
1558         strcat(tsp->data, "\\");
1559         strcat(tsp->data, pathSuffixp);
1560     }
1561     *newSpaceBufferp = tsp;
1562
1563   done:
1564     lock_ReleaseMutex(&linkScp->mx);
1565     return code;
1566 }
1567 #ifdef DEBUG_REFCOUNT
1568 long cm_NameIDbg(cm_scache_t *rootSCachep, char *pathp, long flags,
1569                cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp, 
1570                char * file, long line)
1571 #else
1572 long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
1573                cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp)
1574 #endif
1575 {
1576     long code;
1577     char *tp;                   /* ptr moving through input buffer */
1578     char tc;                    /* temp char */
1579     int haveComponent;          /* has new component started? */
1580     char component[256];        /* this is the new component */
1581     char *cp;                   /* component name being assembled */
1582     cm_scache_t *tscp;          /* current location in the hierarchy */
1583     cm_scache_t *nscp;          /* next dude down */
1584     cm_scache_t *dirScp;        /* last dir we searched */
1585     cm_scache_t *linkScp;       /* new root for the symlink we just
1586     * looked up */
1587     cm_space_t *psp;            /* space for current path, if we've hit
1588     * any symlinks */
1589     cm_space_t *tempsp;         /* temp vbl */
1590     char *restp;                /* rest of the pathname to interpret */
1591     int symlinkCount;           /* count of # of symlinks traversed */
1592     int extraFlag;              /* avoid chasing mt pts for dir cmd */
1593     int phase = 1;              /* 1 = tidPathp, 2 = pathp */
1594
1595 #ifdef DEBUG_REFCOUNT
1596     afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
1597     osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %s tidpath %s flags 0x%x",
1598               rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>", 
1599               flags);
1600 #endif
1601
1602     tp = tidPathp;
1603     if (tp == NULL) {
1604         tp = pathp;
1605         phase = 2;
1606     }
1607     if (tp == NULL) {
1608         tp = "";
1609     }
1610     haveComponent = 0;
1611     psp = NULL;
1612     tscp = rootSCachep;
1613     cm_HoldSCache(tscp);
1614     symlinkCount = 0;
1615     dirScp = NULL;
1616
1617
1618     while (1) {
1619         tc = *tp++;
1620
1621         /* map Unix slashes into DOS ones so we can interpret Unix
1622          * symlinks properly
1623          */
1624         if (tc == '/') 
1625             tc = '\\';
1626
1627         if (!haveComponent) {
1628             if (tc == '\\') {
1629                 continue;
1630             } else if (tc == 0) {
1631                 if (phase == 1) {
1632                     phase = 2;
1633                     tp = pathp;
1634                     continue;
1635                 }
1636                 code = 0;
1637                 break;
1638             } else {
1639                 haveComponent = 1;
1640                 cp = component;
1641                 *cp++ = tc;
1642             }
1643         } else {
1644             /* we have a component here */
1645             if (tc == 0 || tc == '\\') {
1646                 /* end of the component; we're at the last
1647                  * component if tc == 0.  However, if the last
1648                  * is a symlink, we have more to do.
1649                  */
1650                 *cp++ = 0;      /* add null termination */
1651                 if (!strcmp(".",component)) {
1652                     code = 0;
1653                     if (dirScp) {
1654                         cm_ReleaseSCache(dirScp);
1655                         dirScp = NULL;
1656                     }
1657                     break;
1658                 }
1659                 extraFlag = 0;
1660                 if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
1661                     extraFlag = CM_FLAG_NOMOUNTCHASE;
1662                 code = cm_Lookup(tscp, component,
1663                                   flags | extraFlag,
1664                                   userp, reqp, &nscp);
1665                 if (code) {
1666                     cm_ReleaseSCache(tscp);
1667                     if (dirScp)
1668                         cm_ReleaseSCache(dirScp);
1669                     if (psp) 
1670                         cm_FreeSpace(psp);
1671                     if (code == CM_ERROR_NOSUCHFILE && tscp->fileType == CM_SCACHETYPE_SYMLINK) {
1672                         osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_NOSUCHPATH");
1673                         return CM_ERROR_NOSUCHPATH;
1674                     } else {
1675                         osi_Log1(afsd_logp,"cm_NameI code 0x%x", code);
1676                         return code;
1677                     }
1678                 }       
1679                 haveComponent = 0;      /* component done */
1680                 if (dirScp)
1681                     cm_ReleaseSCache(dirScp);
1682                 dirScp = tscp;          /* for some symlinks */
1683                 tscp = nscp;            /* already held */
1684                 nscp = NULL;
1685                 if (tc == 0 && !(flags & CM_FLAG_FOLLOW) && phase == 2) {
1686                     code = 0;
1687                     if (dirScp) {
1688                         cm_ReleaseSCache(dirScp);
1689                         dirScp = NULL;
1690                     }
1691                     break;
1692                 }
1693
1694                 /* now, if tscp is a symlink, we should follow
1695                  * it and assemble the path again.
1696                  */
1697                 lock_ObtainMutex(&tscp->mx);
1698                 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
1699                                   CM_SCACHESYNC_GETSTATUS
1700                                   | CM_SCACHESYNC_NEEDCALLBACK);
1701                 if (code) {
1702                     lock_ReleaseMutex(&tscp->mx);
1703                     cm_ReleaseSCache(tscp);
1704                     tscp = NULL;
1705                     if (dirScp) {
1706                         cm_ReleaseSCache(dirScp);
1707                         dirScp = NULL;
1708                     }
1709                     break;
1710                 }
1711                 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1712
1713                 if (tscp->fileType == CM_SCACHETYPE_SYMLINK) {
1714                     /* this is a symlink; assemble a new buffer */
1715                     lock_ReleaseMutex(&tscp->mx);
1716                     if (symlinkCount++ >= MAX_SYMLINK_COUNT) {
1717                         cm_ReleaseSCache(tscp);
1718                         tscp = NULL;
1719                         if (dirScp) {
1720                             cm_ReleaseSCache(dirScp);
1721                             dirScp = NULL;
1722                         }
1723                         if (psp) 
1724                             cm_FreeSpace(psp);
1725                         osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_TOO_MANY_SYMLINKS");
1726                         return CM_ERROR_TOO_MANY_SYMLINKS;
1727                     }
1728                     if (tc == 0) 
1729                         restp = "";
1730                     else 
1731                         restp = tp;
1732                     code = cm_AssembleLink(tscp, restp, &linkScp, &tempsp, userp, reqp);
1733                     if (code) {
1734                         /* something went wrong */
1735                         cm_ReleaseSCache(tscp);
1736                         tscp = NULL;
1737                         if (dirScp) {
1738                             cm_ReleaseSCache(dirScp);
1739                             dirScp = NULL;
1740                         }
1741                         break;
1742                     }
1743
1744                     /* otherwise, tempsp has the new path,
1745                      * and linkScp is the new root from
1746                      * which to interpret that path.
1747                      * Continue with the namei processing,
1748                      * also doing the bookkeeping for the
1749                      * space allocation and tracking the
1750                      * vnode reference counts.
1751                      */
1752                     if (psp) 
1753                         cm_FreeSpace(psp);
1754                     psp = tempsp;
1755                     tp = psp->data;
1756                     cm_ReleaseSCache(tscp);
1757                     tscp = linkScp;
1758                     linkScp = NULL;
1759                     /* already held
1760                      * by AssembleLink
1761                      * now, if linkScp is null, that's
1762                      * AssembleLink's way of telling us that
1763                      * the sym link is relative to the dir
1764                      * containing the link.  We have a ref
1765                      * to it in dirScp, and we hold it now
1766                      * and reuse it as the new spot in the
1767                      * dir hierarchy.
1768                      */
1769                     if (tscp == NULL) {
1770                         tscp = dirScp;
1771                         dirScp = NULL;
1772                     }
1773                 } else {
1774                     /* not a symlink, we may be done */
1775                     lock_ReleaseMutex(&tscp->mx);
1776                     if (tc == 0) {
1777                         if (phase == 1) {
1778                             phase = 2;
1779                             tp = pathp;
1780                             continue;
1781                         }
1782                         if (dirScp) {
1783                             cm_ReleaseSCache(dirScp);
1784                             dirScp = NULL;
1785                         }
1786                         code = 0;
1787                         break;
1788                     }
1789                 }
1790                 if (dirScp) {
1791                     cm_ReleaseSCache(dirScp);
1792                     dirScp = NULL;
1793                 }
1794             } /* end of a component */
1795             else 
1796                 *cp++ = tc;
1797         } /* we have a component */
1798     } /* big while loop over all components */
1799
1800     /* already held */
1801     if (dirScp)
1802         cm_ReleaseSCache(dirScp);
1803     if (psp) 
1804         cm_FreeSpace(psp);
1805     if (code == 0) 
1806         *outScpp = tscp;
1807     else if (tscp)
1808         cm_ReleaseSCache(tscp);
1809
1810 #ifdef DEBUG_REFCOUNT
1811     afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp)->refCount);
1812 #endif
1813     osi_Log2(afsd_logp,"cm_NameI code 0x%x outScpp 0x%p", code, *outScpp);
1814     return code;
1815 }
1816
1817 /* called with a dir, and a vnode within the dir that happens to be a symlink.
1818  * We chase the link, and return a held pointer to the target, if it exists,
1819  * in *outScpp.  If we succeed, we return 0, otherwise we return an error code
1820  * and do not hold or return a target vnode.
1821  *
1822  * This is very similar to calling cm_NameI with the last component of a name,
1823  * which happens to be a symlink, except that we've already passed by the name.
1824  *
1825  * This function is typically called by the directory listing functions, which
1826  * encounter symlinks but need to return the proper file length so programs
1827  * like "more" work properly when they make use of the attributes retrieved from
1828  * the dir listing.
1829  *
1830  * The input vnode should not be locked when this function is called.
1831  */
1832 long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
1833                          cm_scache_t **outScpp, cm_user_t *userp, cm_req_t *reqp)
1834 {
1835     long code;
1836     cm_space_t *spacep;
1837     cm_scache_t *newRootScp;
1838
1839     osi_Log1(afsd_logp, "Evaluating symlink scp 0x%p", linkScp);
1840
1841     code = cm_AssembleLink(linkScp, "", &newRootScp, &spacep, userp, reqp);
1842     if (code) 
1843         return code;
1844
1845     /* now, if newRootScp is NULL, we're really being told that the symlink
1846      * is relative to the current directory (dscp).
1847      */
1848     if (newRootScp == NULL) {
1849         newRootScp = dscp;
1850         cm_HoldSCache(dscp);
1851     }
1852
1853     code = cm_NameI(newRootScp, spacep->data,
1854                      CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
1855                      userp, NULL, reqp, outScpp);
1856
1857     if (code == CM_ERROR_NOSUCHFILE)
1858         code = CM_ERROR_NOSUCHPATH;
1859
1860     /* this stuff is allocated no matter what happened on the namei call,
1861      * so free it */
1862     cm_FreeSpace(spacep);
1863     cm_ReleaseSCache(newRootScp);
1864
1865     return code;
1866 }
1867
1868 /* make this big enough so that one buffer of dir pages won't overflow.  We'll
1869  * check anyway, but we want to minimize the chance that we have to leave stuff
1870  * unstat'd.
1871  */
1872 #define CM_BULKMAX              (3 * AFSCBMAX)
1873
1874 /* rock for bulk stat calls */
1875 typedef struct cm_bulkStat {
1876     osi_hyper_t bufOffset;      /* only do it for things in this buffer page */
1877
1878     /* info for the actual call */
1879     int counter;                        /* next free slot */
1880     AFSFid fids[CM_BULKMAX];
1881     AFSFetchStatus stats[CM_BULKMAX];
1882     AFSCallBack callbacks[CM_BULKMAX];
1883 } cm_bulkStat_t;
1884
1885 /* for a given entry, make sure that it isn't in the stat cache, and then
1886  * add it to the list of file IDs to be obtained.
1887  *
1888  * Don't bother adding it if we already have a vnode.  Note that the dir
1889  * is locked, so we have to be careful checking the vnode we're thinking of
1890  * processing, to avoid deadlocks.
1891  */
1892 long cm_TryBulkProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1893                      osi_hyper_t *offp)
1894 {
1895     osi_hyper_t thyper;
1896     cm_bulkStat_t *bsp;
1897     int i;
1898     cm_scache_t *tscp;
1899     cm_fid_t tfid;
1900
1901     bsp = rockp;
1902
1903     /* Don't overflow bsp. */
1904     if (bsp->counter >= CM_BULKMAX)
1905         return CM_ERROR_STOPNOW;
1906
1907     thyper.LowPart = cm_data.buf_blockSize;
1908     thyper.HighPart = 0;
1909     thyper = LargeIntegerAdd(thyper, bsp->bufOffset);
1910
1911     /* thyper is now the first byte past the end of the record we're
1912      * interested in, and bsp->bufOffset is the first byte of the record
1913      * we're interested in.
1914      * Skip data in the others.
1915      * Skip '.' and '..'
1916      */
1917     if (LargeIntegerLessThan(*offp, bsp->bufOffset))
1918         return 0;
1919     if (LargeIntegerGreaterThanOrEqualTo(*offp, thyper))
1920         return CM_ERROR_STOPNOW;
1921     if (strcmp(dep->name, ".") == 0 || strcmp(dep->name, "..") == 0)
1922         return 0;
1923
1924     tfid.cell = scp->fid.cell;
1925     tfid.volume = scp->fid.volume;
1926     tfid.vnode = ntohl(dep->fid.vnode);
1927     tfid.unique = ntohl(dep->fid.unique);
1928     tscp = cm_FindSCache(&tfid);
1929     if (tscp) {
1930         if (lock_TryMutex(&tscp->mx)) {
1931             /* we have an entry that we can look at */
1932             if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
1933                 /* we have a callback on it.  Don't bother
1934                  * fetching this stat entry, since we're happy
1935                  * with the info we have.
1936                  */
1937                 lock_ReleaseMutex(&tscp->mx);
1938                 cm_ReleaseSCache(tscp);
1939                 return 0;
1940             }
1941             lock_ReleaseMutex(&tscp->mx);
1942         }       /* got lock */
1943         cm_ReleaseSCache(tscp);
1944     }   /* found entry */
1945
1946 #ifdef AFS_FREELANCE_CLIENT
1947     // yj: if this is a mountpoint under root.afs then we don't want it
1948     // to be bulkstat-ed, instead, we call getSCache directly and under
1949     // getSCache, it is handled specially.
1950     if  ( cm_freelanceEnabled &&
1951           tfid.cell==AFS_FAKE_ROOT_CELL_ID && 
1952           tfid.volume==AFS_FAKE_ROOT_VOL_ID &&
1953           !(tfid.vnode==0x1 && tfid.unique==0x1) )
1954     {       
1955         osi_Log0(afsd_logp, "cm_TryBulkProc Freelance calls cm_SCache on root.afs mountpoint");
1956         return cm_GetSCache(&tfid, &tscp, NULL, NULL);
1957     }
1958 #endif /* AFS_FREELANCE_CLIENT */
1959
1960     i = bsp->counter++;
1961     bsp->fids[i].Volume = scp->fid.volume;
1962     bsp->fids[i].Vnode = tfid.vnode;
1963     bsp->fids[i].Unique = tfid.unique;
1964     return 0;
1965 }       
1966
1967 /* called with a locked scp and a pointer to a buffer.  Make bulk stat
1968  * calls on all undeleted files in the page of the directory specified.
1969  */
1970 afs_int32
1971 cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
1972                cm_req_t *reqp)
1973 {
1974     long code;
1975     cm_bulkStat_t bb;   /* this is *BIG*, probably 16K or so;
1976                          * watch for stack problems */
1977     AFSCBFids fidStruct;
1978     AFSBulkStats statStruct;
1979     cm_conn_t *connp;
1980     AFSCBs callbackStruct;
1981     long filex;
1982     AFSVolSync volSync;
1983     cm_callbackRequest_t cbReq;
1984     long filesThisCall;
1985     long i;
1986     long j;
1987     cm_scache_t *scp;
1988     cm_fid_t tfid;
1989     struct rx_connection * callp;
1990     int inlinebulk = 0;         /* Did we use InlineBulkStatus RPC or not? */
1991
1992     osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
1993
1994     /* should be on a buffer boundary */
1995     osi_assert((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0);
1996
1997     memset(&bb, 0, sizeof(bb));
1998     bb.bufOffset = *offsetp;
1999
2000     lock_ReleaseMutex(&dscp->mx);
2001     /* first, assemble the file IDs we need to stat */
2002     code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) &bb, offsetp, userp, reqp, NULL);
2003
2004     /* if we failed, bail out early */
2005     if (code && code != CM_ERROR_STOPNOW) {
2006         lock_ObtainMutex(&dscp->mx);
2007         return code;
2008     }
2009
2010     /* otherwise, we may have one or more bulk stat's worth of stuff in bb;
2011      * make the calls to create the entries.  Handle AFSCBMAX files at a
2012      * time.
2013      */
2014     filex = 0;
2015     while (filex < bb.counter) {
2016         filesThisCall = bb.counter - filex;
2017         if (filesThisCall > AFSCBMAX) 
2018             filesThisCall = AFSCBMAX;
2019
2020         fidStruct.AFSCBFids_len = filesThisCall;
2021         fidStruct.AFSCBFids_val = &bb.fids[filex];
2022         statStruct.AFSBulkStats_len = filesThisCall;
2023         statStruct.AFSBulkStats_val = &bb.stats[filex];
2024         callbackStruct.AFSCBs_len = filesThisCall;
2025         callbackStruct.AFSCBs_val = &bb.callbacks[filex];
2026         cm_StartCallbackGrantingCall(NULL, &cbReq);
2027         osi_Log1(afsd_logp, "CALL BulkStatus, %d entries", filesThisCall);
2028         do {
2029             code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2030             if (code) 
2031                 continue;
2032
2033             callp = cm_GetRxConn(connp);
2034             if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
2035                 code = RXAFS_InlineBulkStatus(callp, &fidStruct,
2036                                      &statStruct, &callbackStruct, &volSync);
2037                 if (code == RXGEN_OPCODE) {
2038                     cm_SetServerNoInlineBulk(connp->serverp, 0);
2039                 } else {
2040                     inlinebulk = 1;
2041                 }
2042             }
2043             if (!inlinebulk) {
2044                 code = RXAFS_BulkStatus(callp, &fidStruct,
2045                                         &statStruct, &callbackStruct, &volSync);
2046             }
2047             rx_PutConnection(callp);
2048
2049         } while (cm_Analyze(connp, userp, reqp, &dscp->fid,
2050                              &volSync, NULL, &cbReq, code));
2051         code = cm_MapRPCError(code, reqp);
2052         if (code)
2053             osi_Log2(afsd_logp, "CALL %sBulkStatus FAILURE code 0x%x", 
2054                       inlinebulk ? "Inline" : "", code);
2055         else
2056             osi_Log1(afsd_logp, "CALL %sBulkStatus SUCCESS", inlinebulk ? "Inline" : "");
2057
2058         /* may as well quit on an error, since we're not going to do
2059          * much better on the next immediate call, either.
2060          */
2061         if (code) {
2062             cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
2063             break;
2064         }
2065
2066         /* otherwise, we should do the merges */
2067         for (i = 0; i<filesThisCall; i++) {
2068             j = filex + i;
2069             tfid.cell = dscp->fid.cell;
2070             tfid.volume = bb.fids[j].Volume;
2071             tfid.vnode = bb.fids[j].Vnode;
2072             tfid.unique = bb.fids[j].Unique;
2073             code = cm_GetSCache(&tfid, &scp, userp, reqp);
2074             if (code != 0) 
2075                 continue;
2076
2077             /* otherwise, if this entry has no callback info, 
2078              * merge in this.
2079              */
2080             lock_ObtainMutex(&scp->mx);
2081             /* now, we have to be extra paranoid on merging in this
2082              * information, since we didn't use cm_SyncOp before
2083              * starting the fetch to make sure that no bad races
2084              * were occurring.  Specifically, we need to make sure
2085              * we don't obliterate any newer information in the
2086              * vnode than have here.
2087              *
2088              * Right now, be pretty conservative: if there's a
2089              * callback or a pending call, skip it.
2090              */
2091             if ((scp->cbServerp == NULL || (scp->flags & CM_SCACHEFLAG_EACCESS))
2092                  && !(scp->flags &
2093                        (CM_SCACHEFLAG_FETCHING
2094                          | CM_SCACHEFLAG_STORING
2095                          | CM_SCACHEFLAG_SIZESTORING))) {
2096                 cm_EndCallbackGrantingCall(scp, &cbReq,
2097                                             &bb.callbacks[j],
2098                                             CM_CALLBACK_MAINTAINCOUNT);
2099                 cm_MergeStatus(scp, &bb.stats[j], &volSync, userp, 0);
2100             }       
2101             lock_ReleaseMutex(&scp->mx);
2102             cm_ReleaseSCache(scp);
2103         } /* all files in the response */
2104         /* now tell it to drop the count,
2105          * after doing the vnode processing above */
2106         cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
2107
2108         filex += filesThisCall;
2109     }   /* while there are still more files to process */
2110     lock_ObtainMutex(&dscp->mx);
2111
2112 #if 0
2113     /* If we did the InlineBulk RPC pull out the return code */
2114     if (inlinebulk) {
2115         if ((&bb.stats[0])->errorCode) {
2116             cm_Analyze(NULL /*connp was released by the previous cm_Analyze */, 
2117                         userp, reqp, &dscp->fid, &volSync, NULL, NULL, (&bb.stats[0])->errorCode);
2118             code = cm_MapRPCError((&bb.stats[0])->errorCode, reqp);
2119         }
2120     } else
2121 #endif  
2122     { 
2123         code = 0;
2124     }
2125
2126     osi_Log1(afsd_logp, "END cm_TryBulkStat code = 0x%x", code);
2127     return code;
2128 }       
2129
2130 void cm_StatusFromAttr(AFSStoreStatus *statusp, cm_scache_t *scp, cm_attr_t *attrp)
2131 {
2132     long mask;
2133
2134     /* initialize store back mask as inexpensive local variable */
2135     mask = 0;
2136     memset(statusp, 0, sizeof(AFSStoreStatus));
2137
2138     /* copy out queued info from scache first, if scp passed in */
2139     if (scp) {
2140         if (scp->mask & CM_SCACHEMASK_CLIENTMODTIME) {
2141             statusp->ClientModTime = scp->clientModTime;
2142             mask |= AFS_SETMODTIME;
2143             scp->mask &= ~CM_SCACHEMASK_CLIENTMODTIME;
2144         }
2145     }
2146
2147     if (attrp) {
2148         /* now add in our locally generated request */
2149         if (attrp->mask & CM_ATTRMASK_CLIENTMODTIME) {
2150             statusp->ClientModTime = attrp->clientModTime;
2151             mask |= AFS_SETMODTIME;
2152         }
2153         if (attrp->mask & CM_ATTRMASK_UNIXMODEBITS) {
2154             statusp->UnixModeBits = attrp->unixModeBits;
2155             mask |= AFS_SETMODE;
2156         }
2157         if (attrp->mask & CM_ATTRMASK_OWNER) {
2158             statusp->Owner = attrp->owner;
2159             mask |= AFS_SETOWNER;
2160         }
2161         if (attrp->mask & CM_ATTRMASK_GROUP) {
2162             statusp->Group = attrp->group;
2163             mask |= AFS_SETGROUP;
2164         }
2165     }
2166     statusp->Mask = mask;
2167 }       
2168
2169 /* set the file size, and make sure that all relevant buffers have been
2170  * truncated.  Ensure that any partially truncated buffers have been zeroed
2171  * to the end of the buffer.
2172  */
2173 long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
2174                    cm_req_t *reqp)
2175 {
2176     long code;
2177     int shrinking;
2178
2179     /* start by locking out buffer creation */
2180     lock_ObtainWrite(&scp->bufCreateLock);
2181
2182     /* verify that this is a file, not a dir or a symlink */
2183     lock_ObtainMutex(&scp->mx);
2184     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2185                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2186     if (code) 
2187         goto done;
2188     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2189
2190     if (scp->fileType != CM_SCACHETYPE_FILE) {
2191         code = CM_ERROR_ISDIR;
2192         goto done;
2193     }
2194
2195   startover:
2196     if (LargeIntegerLessThan(*sizep, scp->length))
2197         shrinking = 1;
2198     else
2199         shrinking = 0;
2200
2201     lock_ReleaseMutex(&scp->mx);
2202
2203     /* can't hold scp->mx lock here, since we may wait for a storeback to
2204      * finish if the buffer package is cleaning a buffer by storing it to
2205      * the server.
2206      */
2207     if (shrinking)
2208         buf_Truncate(scp, userp, reqp, sizep);
2209
2210     /* now ensure that file length is short enough, and update truncPos */
2211     lock_ObtainMutex(&scp->mx);
2212
2213     /* make sure we have a callback (so we have the right value for the
2214      * length), and wait for it to be safe to do a truncate.
2215      */
2216     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_WRITE,
2217                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
2218                       | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
2219     if (code) 
2220         goto done;
2221
2222     if (LargeIntegerLessThan(*sizep, scp->length)) {
2223         /* a real truncation.  If truncPos is not set yet, or is bigger
2224          * than where we're truncating the file, set truncPos to this
2225          * new value.
2226          */
2227         if (!shrinking)
2228             goto startover;
2229         if (!(scp->mask & CM_SCACHEMASK_TRUNCPOS)
2230              || LargeIntegerLessThan(*sizep, scp->length)) {
2231             /* set trunc pos */
2232             scp->truncPos = *sizep;
2233             scp->mask |= CM_SCACHEMASK_TRUNCPOS;
2234         }
2235         /* in either case, the new file size has been changed */
2236         scp->length = *sizep;
2237         scp->mask |= CM_SCACHEMASK_LENGTH;
2238     }
2239     else if (LargeIntegerGreaterThan(*sizep, scp->length)) {
2240         /* really extending the file */
2241         scp->length = *sizep;
2242         scp->mask |= CM_SCACHEMASK_LENGTH;
2243     }
2244
2245     /* done successfully */
2246     code = 0;
2247
2248     cm_SyncOpDone(scp, NULL, 
2249                    CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
2250                    | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
2251
2252   done:
2253     lock_ReleaseMutex(&scp->mx);
2254     lock_ReleaseWrite(&scp->bufCreateLock);
2255
2256     return code;
2257 }
2258
2259 /* set the file size or other attributes (but not both at once) */
2260 long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
2261                 cm_req_t *reqp)
2262 {
2263     long code;
2264     AFSFetchStatus afsOutStatus;
2265     AFSVolSync volSync;
2266     cm_conn_t *connp;
2267     AFSFid tfid;
2268     AFSStoreStatus afsInStatus;
2269     struct rx_connection * callp;
2270
2271     /* handle file length setting */
2272     if (attrp->mask & CM_ATTRMASK_LENGTH)
2273         return cm_SetLength(scp, &attrp->length, userp, reqp);
2274
2275     lock_ObtainMutex(&scp->mx);
2276     /* otherwise, we have to make an RPC to get the status */
2277     code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
2278     if (code) {
2279         lock_ReleaseMutex(&scp->mx);
2280         return code;
2281     }
2282
2283     /* make the attr structure */
2284     cm_StatusFromAttr(&afsInStatus, scp, attrp);
2285
2286     tfid.Volume = scp->fid.volume;
2287     tfid.Vnode = scp->fid.vnode;
2288     tfid.Unique = scp->fid.unique;
2289         lock_ReleaseMutex(&scp->mx);
2290
2291     /* now make the RPC */
2292     osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
2293     do {
2294         code = cm_Conn(&scp->fid, userp, reqp, &connp);
2295         if (code) 
2296             continue;
2297
2298         callp = cm_GetRxConn(connp);
2299         code = RXAFS_StoreStatus(callp, &tfid,
2300                                   &afsInStatus, &afsOutStatus, &volSync);
2301         rx_PutConnection(callp);
2302
2303     } while (cm_Analyze(connp, userp, reqp,
2304                          &scp->fid, &volSync, NULL, NULL, code));
2305     code = cm_MapRPCError(code, reqp);
2306
2307     if (code)
2308         osi_Log1(afsd_logp, "CALL StoreStatus FAILURE, code 0x%x", code);
2309     else
2310         osi_Log0(afsd_logp, "CALL StoreStatus SUCCESS");
2311
2312     lock_ObtainMutex(&scp->mx);
2313     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
2314     if (code == 0)
2315         cm_MergeStatus(scp, &afsOutStatus, &volSync, userp,
2316                         CM_MERGEFLAG_FORCE);
2317         
2318     /* if we're changing the mode bits, discard the ACL cache, 
2319      * since we changed the mode bits.
2320      */
2321     if (afsInStatus.Mask & AFS_SETMODE) cm_FreeAllACLEnts(scp);
2322     lock_ReleaseMutex(&scp->mx);
2323     return code;
2324 }       
2325
2326 long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
2327                cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp)
2328 {       
2329     cm_conn_t *connp;
2330     long code;
2331     AFSFid dirAFSFid;
2332     cm_callbackRequest_t cbReq;
2333     AFSFid newAFSFid;
2334     cm_fid_t newFid;
2335     cm_scache_t *scp;
2336     int didEnd;
2337     AFSStoreStatus inStatus;
2338     AFSFetchStatus updatedDirStatus;
2339     AFSFetchStatus newFileStatus;
2340     AFSCallBack newFileCallback;
2341     AFSVolSync volSync;
2342     struct rx_connection * callp;
2343
2344     /* can't create names with @sys in them; must expand it manually first.
2345      * return "invalid request" if they try.
2346      */
2347     if (cm_ExpandSysName(namep, NULL, 0, 0)) {
2348         return CM_ERROR_ATSYS;
2349     }
2350
2351     /* before starting the RPC, mark that we're changing the file data, so
2352      * that someone who does a chmod will know to wait until our call
2353      * completes.
2354      */
2355     lock_ObtainMutex(&dscp->mx);
2356     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2357     if (code == 0) {
2358         cm_StartCallbackGrantingCall(NULL, &cbReq);
2359     }
2360     lock_ReleaseMutex(&dscp->mx);
2361     if (code) {
2362         return code;
2363     }
2364     didEnd = 0;
2365
2366     cm_StatusFromAttr(&inStatus, NULL, attrp);
2367
2368     /* try the RPC now */
2369     osi_Log1(afsd_logp, "CALL CreateFile scp 0x%p", dscp);
2370     do {
2371         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2372         if (code) 
2373             continue;
2374
2375         dirAFSFid.Volume = dscp->fid.volume;
2376         dirAFSFid.Vnode = dscp->fid.vnode;
2377         dirAFSFid.Unique = dscp->fid.unique;
2378
2379         callp = cm_GetRxConn(connp);
2380         code = RXAFS_CreateFile(connp->callp, &dirAFSFid, namep,
2381                                  &inStatus, &newAFSFid, &newFileStatus,
2382                                  &updatedDirStatus, &newFileCallback,
2383                                  &volSync);
2384         rx_PutConnection(callp);
2385
2386     } while (cm_Analyze(connp, userp, reqp,
2387                          &dscp->fid, &volSync, NULL, &cbReq, code));
2388     code = cm_MapRPCError(code, reqp);
2389         
2390     if (code)
2391         osi_Log1(afsd_logp, "CALL CreateFile FAILURE, code 0x%x", code);
2392     else
2393         osi_Log0(afsd_logp, "CALL CreateFile SUCCESS");
2394
2395     lock_ObtainMutex(&dscp->mx);
2396     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2397     if (code == 0) {
2398         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2399     }
2400     lock_ReleaseMutex(&dscp->mx);
2401
2402     /* now try to create the file's entry, too, but be careful to 
2403      * make sure that we don't merge in old info.  Since we weren't locking
2404      * out any requests during the file's creation, we may have pretty old
2405      * info.
2406      */
2407     if (code == 0) {
2408         newFid.cell = dscp->fid.cell;
2409         newFid.volume = dscp->fid.volume;
2410         newFid.vnode = newAFSFid.Vnode;
2411         newFid.unique = newAFSFid.Unique;
2412         code = cm_GetSCache(&newFid, &scp, userp, reqp);
2413         if (code == 0) {
2414             lock_ObtainMutex(&scp->mx);
2415             scp->creator = userp;               /* remember who created it */
2416             if (!cm_HaveCallback(scp)) {
2417                 cm_MergeStatus(scp, &newFileStatus, &volSync,
2418                                 userp, 0);
2419                 cm_EndCallbackGrantingCall(scp, &cbReq,
2420                                             &newFileCallback, 0);
2421                 didEnd = 1;     
2422             }       
2423             lock_ReleaseMutex(&scp->mx);
2424             *scpp = scp;
2425         }
2426     }
2427
2428     /* make sure we end things properly */
2429     if (!didEnd)
2430         cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
2431
2432     return code;
2433 }       
2434
2435 long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
2436 {
2437     long code;
2438
2439     lock_ObtainWrite(&scp->bufCreateLock);
2440     code = buf_CleanVnode(scp, userp, reqp);
2441     lock_ReleaseWrite(&scp->bufCreateLock);
2442     if (code == 0) {
2443         lock_ObtainMutex(&scp->mx);
2444
2445         if (scp->mask & (CM_SCACHEMASK_TRUNCPOS
2446                           | CM_SCACHEMASK_CLIENTMODTIME
2447                           | CM_SCACHEMASK_LENGTH))
2448             code = cm_StoreMini(scp, userp, reqp);
2449
2450         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
2451             code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
2452             scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE);
2453         }
2454
2455         lock_ReleaseMutex(&scp->mx);
2456     }
2457     return code;
2458 }
2459
2460 long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
2461                  cm_user_t *userp, cm_req_t *reqp)
2462 {
2463     cm_conn_t *connp;
2464     long code;
2465     AFSFid dirAFSFid;
2466     cm_callbackRequest_t cbReq;
2467     AFSFid newAFSFid;
2468     cm_fid_t newFid;
2469     cm_scache_t *scp;
2470     int didEnd;
2471     AFSStoreStatus inStatus;
2472     AFSFetchStatus updatedDirStatus;
2473     AFSFetchStatus newDirStatus;
2474     AFSCallBack newDirCallback;
2475     AFSVolSync volSync;
2476     struct rx_connection * callp;
2477
2478     /* can't create names with @sys in them; must expand it manually first.
2479      * return "invalid request" if they try.
2480      */
2481     if (cm_ExpandSysName(namep, NULL, 0, 0)) {
2482         return CM_ERROR_ATSYS;
2483     }
2484
2485     /* before starting the RPC, mark that we're changing the directory
2486      * data, so that someone who does a chmod on the dir will wait until
2487      * our call completes.
2488      */
2489     lock_ObtainMutex(&dscp->mx);
2490     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2491     if (code == 0) {
2492         cm_StartCallbackGrantingCall(NULL, &cbReq);
2493     }
2494     lock_ReleaseMutex(&dscp->mx);
2495     if (code) {
2496         return code;
2497     }
2498     didEnd = 0;
2499
2500     cm_StatusFromAttr(&inStatus, NULL, attrp);
2501
2502     /* try the RPC now */
2503     osi_Log1(afsd_logp, "CALL MakeDir scp 0x%p", dscp);
2504     do {
2505         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2506         if (code) 
2507             continue;
2508
2509         dirAFSFid.Volume = dscp->fid.volume;
2510         dirAFSFid.Vnode = dscp->fid.vnode;
2511         dirAFSFid.Unique = dscp->fid.unique;
2512
2513         callp = cm_GetRxConn(connp);
2514         code = RXAFS_MakeDir(connp->callp, &dirAFSFid, namep,
2515                               &inStatus, &newAFSFid, &newDirStatus,
2516                               &updatedDirStatus, &newDirCallback,
2517                               &volSync);
2518         rx_PutConnection(callp);
2519
2520     } while (cm_Analyze(connp, userp, reqp,
2521                          &dscp->fid, &volSync, NULL, &cbReq, code));
2522     code = cm_MapRPCError(code, reqp);
2523         
2524     if (code)
2525         osi_Log1(afsd_logp, "CALL MakeDir FAILURE, code 0x%x", code);
2526     else
2527         osi_Log0(afsd_logp, "CALL MakeDir SUCCESS");
2528
2529     lock_ObtainMutex(&dscp->mx);
2530     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2531     if (code == 0) {
2532         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2533     }
2534     lock_ReleaseMutex(&dscp->mx);
2535
2536     /* now try to create the new dir's entry, too, but be careful to 
2537      * make sure that we don't merge in old info.  Since we weren't locking
2538      * out any requests during the file's creation, we may have pretty old
2539      * info.
2540      */
2541     if (code == 0) {
2542         newFid.cell = dscp->fid.cell;
2543         newFid.volume = dscp->fid.volume;
2544         newFid.vnode = newAFSFid.Vnode;
2545         newFid.unique = newAFSFid.Unique;
2546         code = cm_GetSCache(&newFid, &scp, userp, reqp);
2547         if (code == 0) {
2548             lock_ObtainMutex(&scp->mx);
2549             if (!cm_HaveCallback(scp)) {
2550                 cm_MergeStatus(scp, &newDirStatus, &volSync,
2551                                 userp, 0);
2552                 cm_EndCallbackGrantingCall(scp, &cbReq,
2553                                             &newDirCallback, 0);
2554                 didEnd = 1;             
2555             }
2556             lock_ReleaseMutex(&scp->mx);
2557             cm_ReleaseSCache(scp);
2558         }
2559     }
2560
2561     /* make sure we end things properly */
2562     if (!didEnd)
2563         cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
2564
2565     /* and return error code */
2566     return code;
2567 }       
2568
2569 long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
2570              cm_user_t *userp, cm_req_t *reqp)
2571 {
2572     cm_conn_t *connp;
2573     long code = 0;
2574     AFSFid dirAFSFid;
2575     AFSFid existingAFSFid;
2576     AFSFetchStatus updatedDirStatus;
2577     AFSFetchStatus newLinkStatus;
2578     AFSVolSync volSync;
2579     struct rx_connection * callp;
2580
2581     if (dscp->fid.cell != sscp->fid.cell ||
2582         dscp->fid.volume != sscp->fid.volume) {
2583         return CM_ERROR_CROSSDEVLINK;
2584     }
2585
2586     lock_ObtainMutex(&dscp->mx);
2587     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2588     lock_ReleaseMutex(&dscp->mx);
2589
2590     if (code)
2591         return code;
2592
2593     /* try the RPC now */
2594     osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
2595     do {
2596         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2597         if (code) continue;
2598
2599         dirAFSFid.Volume = dscp->fid.volume;
2600         dirAFSFid.Vnode = dscp->fid.vnode;
2601         dirAFSFid.Unique = dscp->fid.unique;
2602
2603         existingAFSFid.Volume = sscp->fid.volume;
2604         existingAFSFid.Vnode = sscp->fid.vnode;
2605         existingAFSFid.Unique = sscp->fid.unique;
2606
2607         callp = cm_GetRxConn(connp);
2608         code = RXAFS_Link(callp, &dirAFSFid, namep, &existingAFSFid,
2609             &newLinkStatus, &updatedDirStatus, &volSync);
2610         rx_PutConnection(callp);
2611         osi_Log1(smb_logp,"  RXAFS_Link returns 0x%x", code);
2612
2613     } while (cm_Analyze(connp, userp, reqp,
2614         &dscp->fid, &volSync, NULL, NULL, code));
2615
2616     code = cm_MapRPCError(code, reqp);
2617
2618     if (code)
2619         osi_Log1(afsd_logp, "CALL Link FAILURE, code 0x%x", code);
2620     else
2621         osi_Log0(afsd_logp, "CALL Link SUCCESS");
2622
2623     lock_ObtainMutex(&dscp->mx);
2624     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2625     if (code == 0) {
2626         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2627     }
2628     lock_ReleaseMutex(&dscp->mx);
2629
2630     return code;
2631 }
2632
2633 long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
2634                 cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp)
2635 {
2636     cm_conn_t *connp;
2637     long code;
2638     AFSFid dirAFSFid;
2639     AFSFid newAFSFid;
2640     cm_fid_t newFid;
2641     cm_scache_t *scp;
2642     AFSStoreStatus inStatus;
2643     AFSFetchStatus updatedDirStatus;
2644     AFSFetchStatus newLinkStatus;
2645     AFSVolSync volSync;
2646     struct rx_connection * callp;
2647
2648     /* before starting the RPC, mark that we're changing the directory data,
2649      * so that someone who does a chmod on the dir will wait until our
2650      * call completes.
2651      */
2652     lock_ObtainMutex(&dscp->mx);
2653     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2654     lock_ReleaseMutex(&dscp->mx);
2655     if (code) {
2656         return code;
2657     }
2658
2659     cm_StatusFromAttr(&inStatus, NULL, attrp);
2660
2661     /* try the RPC now */
2662     osi_Log1(afsd_logp, "CALL Symlink scp 0x%p", dscp);
2663     do {
2664         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2665         if (code) 
2666             continue;
2667
2668         dirAFSFid.Volume = dscp->fid.volume;
2669         dirAFSFid.Vnode = dscp->fid.vnode;
2670         dirAFSFid.Unique = dscp->fid.unique;
2671
2672         callp = cm_GetRxConn(connp);
2673         code = RXAFS_Symlink(callp, &dirAFSFid, namep, contentsp,
2674                               &inStatus, &newAFSFid, &newLinkStatus,
2675                               &updatedDirStatus, &volSync);
2676         rx_PutConnection(callp);
2677
2678     } while (cm_Analyze(connp, userp, reqp,
2679                          &dscp->fid, &volSync, NULL, NULL, code));
2680     code = cm_MapRPCError(code, reqp);
2681         
2682     if (code)
2683         osi_Log1(afsd_logp, "CALL Symlink FAILURE, code 0x%x", code);
2684     else
2685         osi_Log0(afsd_logp, "CALL Symlink SUCCESS");
2686
2687     lock_ObtainMutex(&dscp->mx);
2688     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2689     if (code == 0) {
2690         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2691     }
2692     lock_ReleaseMutex(&dscp->mx);
2693
2694     /* now try to create the new dir's entry, too, but be careful to 
2695      * make sure that we don't merge in old info.  Since we weren't locking
2696      * out any requests during the file's creation, we may have pretty old
2697      * info.
2698      */
2699     if (code == 0) {
2700         newFid.cell = dscp->fid.cell;
2701         newFid.volume = dscp->fid.volume;
2702         newFid.vnode = newAFSFid.Vnode;
2703         newFid.unique = newAFSFid.Unique;
2704         code = cm_GetSCache(&newFid, &scp, userp, reqp);
2705         if (code == 0) {
2706             lock_ObtainMutex(&scp->mx);
2707             if (!cm_HaveCallback(scp)) {
2708                 cm_MergeStatus(scp, &newLinkStatus, &volSync,
2709                                 userp, 0);
2710             }       
2711             lock_ReleaseMutex(&scp->mx);
2712             cm_ReleaseSCache(scp);
2713         }
2714     }
2715         
2716     /* and return error code */
2717     return code;
2718 }
2719
2720 long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
2721                    cm_req_t *reqp)
2722 {
2723     cm_conn_t *connp;
2724     long code;
2725     AFSFid dirAFSFid;
2726     int didEnd;
2727     AFSFetchStatus updatedDirStatus;
2728     AFSVolSync volSync;
2729     struct rx_connection * callp;
2730
2731     /* before starting the RPC, mark that we're changing the directory data,
2732      * so that someone who does a chmod on the dir will wait until our
2733      * call completes.
2734      */
2735     lock_ObtainMutex(&dscp->mx);
2736     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2737     lock_ReleaseMutex(&dscp->mx);
2738     if (code) {
2739         return code;
2740     }
2741     didEnd = 0;
2742
2743     /* try the RPC now */
2744     osi_Log1(afsd_logp, "CALL RemoveDir scp 0x%p", dscp);
2745     do {
2746         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2747         if (code) 
2748             continue;
2749
2750         dirAFSFid.Volume = dscp->fid.volume;
2751         dirAFSFid.Vnode = dscp->fid.vnode;
2752         dirAFSFid.Unique = dscp->fid.unique;
2753
2754         callp = cm_GetRxConn(connp);
2755         code = RXAFS_RemoveDir(callp, &dirAFSFid, namep,
2756                                 &updatedDirStatus, &volSync);
2757         rx_PutConnection(callp);
2758
2759     } while (cm_Analyze(connp, userp, reqp,
2760                          &dscp->fid, &volSync, NULL, NULL, code));
2761     code = cm_MapRPCErrorRmdir(code, reqp);
2762
2763     if (code)
2764         osi_Log1(afsd_logp, "CALL RemoveDir FAILURE, code 0x%x", code);
2765     else
2766         osi_Log0(afsd_logp, "CALL RemoveDir SUCCESS");
2767
2768     lock_ObtainMutex(&dscp->mx);
2769     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2770     if (code == 0) {
2771         cm_dnlcRemove(dscp, namep); 
2772         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2773     }
2774     lock_ReleaseMutex(&dscp->mx);
2775
2776     /* and return error code */
2777     return code;
2778 }
2779
2780 long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
2781 {
2782     /* grab mutex on contents */
2783     lock_ObtainMutex(&scp->mx);
2784
2785     /* reset the prefetch info */
2786     scp->prefetch.base.LowPart = 0;             /* base */
2787     scp->prefetch.base.HighPart = 0;
2788     scp->prefetch.end.LowPart = 0;              /* and end */
2789     scp->prefetch.end.HighPart = 0;
2790
2791     /* release mutex on contents */
2792     lock_ReleaseMutex(&scp->mx);
2793
2794     /* we're done */
2795     return 0;
2796 }       
2797
2798 long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
2799                 char *newNamep, cm_user_t *userp, cm_req_t *reqp)
2800 {
2801     cm_conn_t *connp;
2802     long code;
2803     AFSFid oldDirAFSFid;
2804     AFSFid newDirAFSFid;
2805     int didEnd;
2806     AFSFetchStatus updatedOldDirStatus;
2807     AFSFetchStatus updatedNewDirStatus;
2808     AFSVolSync volSync;
2809     int oneDir;
2810     struct rx_connection * callp;
2811
2812     /* before starting the RPC, mark that we're changing the directory data,
2813      * so that someone who does a chmod on the dir will wait until our call
2814      * completes.  We do this in vnode order so that we don't deadlock,
2815      * which makes the code a little verbose.
2816      */
2817     if (oldDscp == newDscp) {
2818         /* check for identical names */
2819         if (strcmp(oldNamep, newNamep) == 0)
2820             return CM_ERROR_RENAME_IDENTICAL;
2821
2822         oneDir = 1;
2823         lock_ObtainMutex(&oldDscp->mx);
2824         cm_dnlcRemove(oldDscp, oldNamep);
2825         cm_dnlcRemove(oldDscp, newNamep);
2826         code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
2827                           CM_SCACHESYNC_STOREDATA);
2828         lock_ReleaseMutex(&oldDscp->mx);
2829     }
2830     else {
2831         /* two distinct dir vnodes */
2832         oneDir = 0;
2833         if (oldDscp->fid.cell != newDscp->fid.cell ||
2834              oldDscp->fid.volume != newDscp->fid.volume)
2835             return CM_ERROR_CROSSDEVLINK;
2836
2837         /* shouldn't happen that we have distinct vnodes for two
2838          * different files, but could due to deliberate attack, or
2839          * stale info.  Avoid deadlocks and quit now.
2840          */
2841         if (oldDscp->fid.vnode == newDscp->fid.vnode)
2842             return CM_ERROR_CROSSDEVLINK;
2843
2844         if (oldDscp->fid.vnode < newDscp->fid.vnode) {
2845             lock_ObtainMutex(&oldDscp->mx);
2846             cm_dnlcRemove(oldDscp, oldNamep);
2847             code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
2848                               CM_SCACHESYNC_STOREDATA);
2849             lock_ReleaseMutex(&oldDscp->mx);
2850             if (code == 0) {
2851                 lock_ObtainMutex(&newDscp->mx);
2852                 cm_dnlcRemove(newDscp, newNamep);
2853                 code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
2854                                   CM_SCACHESYNC_STOREDATA);
2855                 lock_ReleaseMutex(&newDscp->mx);
2856                 if (code) {
2857                     /* cleanup first one */
2858                     lock_ObtainMutex(&oldDscp->mx);
2859                     cm_SyncOpDone(oldDscp, NULL,
2860                                    CM_SCACHESYNC_STOREDATA);
2861                     lock_ReleaseMutex(&oldDscp->mx);
2862                 }       
2863             }
2864         }
2865         else {
2866             /* lock the new vnode entry first */
2867             lock_ObtainMutex(&newDscp->mx);
2868             cm_dnlcRemove(newDscp, newNamep);
2869             code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
2870                               CM_SCACHESYNC_STOREDATA);
2871             lock_ReleaseMutex(&newDscp->mx);
2872             if (code == 0) {
2873                 lock_ObtainMutex(&oldDscp->mx);
2874                 cm_dnlcRemove(oldDscp, oldNamep);
2875                 code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
2876                                   CM_SCACHESYNC_STOREDATA);
2877                 lock_ReleaseMutex(&oldDscp->mx);
2878                 if (code) {
2879                     /* cleanup first one */
2880                     lock_ObtainMutex(&newDscp->mx);
2881                     cm_SyncOpDone(newDscp, NULL,
2882                                    CM_SCACHESYNC_STOREDATA);
2883                     lock_ReleaseMutex(&newDscp->mx);
2884                 }       
2885             }
2886         }
2887     }   /* two distinct vnodes */
2888
2889     if (code) {
2890         return code;
2891     }
2892     didEnd = 0;
2893
2894     /* try the RPC now */
2895     osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p", 
2896               oldDscp, newDscp);
2897     do {
2898         code = cm_Conn(&oldDscp->fid, userp, reqp, &connp);
2899         if (code) 
2900             continue;
2901
2902         oldDirAFSFid.Volume = oldDscp->fid.volume;
2903         oldDirAFSFid.Vnode = oldDscp->fid.vnode;
2904         oldDirAFSFid.Unique = oldDscp->fid.unique;
2905         newDirAFSFid.Volume = newDscp->fid.volume;
2906         newDirAFSFid.Vnode = newDscp->fid.vnode;
2907         newDirAFSFid.Unique = newDscp->fid.unique;
2908
2909         callp = cm_GetRxConn(connp);
2910         code = RXAFS_Rename(callp, &oldDirAFSFid, oldNamep,
2911                              &newDirAFSFid, newNamep,
2912                              &updatedOldDirStatus, &updatedNewDirStatus,
2913                              &volSync);
2914         rx_PutConnection(callp);
2915
2916     } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
2917                          &volSync, NULL, NULL, code));
2918     code = cm_MapRPCError(code, reqp);
2919         
2920     if (code)
2921         osi_Log1(afsd_logp, "CALL Rename FAILURE, code 0x%x", code);
2922     else
2923         osi_Log0(afsd_logp, "CALL Rename SUCCESS");
2924
2925     /* update the individual stat cache entries for the directories */
2926     lock_ObtainMutex(&oldDscp->mx);
2927     cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
2928     if (code == 0) {
2929         cm_MergeStatus(oldDscp, &updatedOldDirStatus, &volSync,
2930                         userp, 0);
2931     }
2932     lock_ReleaseMutex(&oldDscp->mx);
2933
2934     /* and update it for the new one, too, if necessary */
2935     if (!oneDir) {
2936         lock_ObtainMutex(&newDscp->mx);
2937         cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
2938         if (code == 0) {
2939             cm_MergeStatus(newDscp, &updatedNewDirStatus, &volSync,
2940                             userp, 0);
2941         }
2942         lock_ReleaseMutex(&newDscp->mx);
2943     }
2944
2945     /* and return error code */
2946     return code;
2947 }
2948
2949 /* Byte range locks:
2950
2951    The OpenAFS Windows client has to fake byte range locks given no
2952    server side support for such locks.  This is implemented as keyed
2953    byte range locks on the cache manager.
2954
2955    Keyed byte range locks:
2956
2957    Each cm_scache_t structure keeps track of a list of keyed locks.
2958    The key for a lock identifies an owner of a set of locks (referred
2959    to as a client).  Each key is represented by a value.  The set of
2960    key values used within a specific cm_scache_t structure form a
2961    namespace that has a scope of just that cm_scache_t structure.  The
2962    same key value can be used with another cm_scache_t structure and
2963    correspond to a completely different client.  However it is
2964    advantageous for the SMB or IFS layer to make sure that there is a
2965    1-1 mapping between client and keys over all cm_scache_t objects.
2966
2967    Assume a client C has key Key(C) (although, since the scope of the
2968    key is a cm_scache_t, the key can be Key(C,S), where S is the
2969    cm_scache_t.  But assume a 1-1 relation between keys and clients).
2970    A byte range (O,+L) denotes byte addresses (O) through (O+L-1)
2971    inclusive (a.k.a. [O,O+L-1]).  The function Key(x) is implemented
2972    through cm_generateKey() function for both SMB and IFS.
2973
2974    The list of locks for a cm_scache_t object S is maintained in
2975    S->fileLocks.  The cache manager will set a lock on the AFS file
2976    server in order to assert the locks in S->fileLocks.  If only
2977    shared locks are in place for S, then the cache manager will obtain
2978    a LockRead lock, while if there are any exclusive locks, it will
2979    obtain a LockWrite lock.  If the exclusive locks are all released
2980    while the shared locks remain, then the cache manager will
2981    downgrade the lock from LockWrite to LockRead.  Similarly, if an
2982    exclusive lock is obtained when only shared locks exist, then the
2983    cache manager will try to upgrade the lock from LockRead to
2984    LockWrite.
2985
2986    Each lock L owned by client C maintains a key L->key such that
2987    L->key == Key(C), the effective range defined by L->LOffset and
2988    L->LLength such that the range of bytes affected by the lock is
2989    (L->LOffset, +L->LLength), a type maintained in L->LockType which
2990    is either exclusive or shared.
2991
2992    Lock states:
2993
2994    A lock exists iff it is in S->fileLocks for some cm_scache_t
2995    S. Existing locks are in one of the following states: ACTIVE,
2996    WAITLOCK, WAITUNLOCK, LOST, DELETED.
2997
2998    The following sections describe each lock and the associated
2999    transitions.
3000
3001    1. ACTIVE: A lock L is ACTIVE iff the cache manager has asserted
3002       the lock with the AFS file server.  This type of lock can be
3003       exercised by a client to read or write to the locked region (as
3004       the lock allows).
3005
3006       1.1 ACTIVE->LOST: When the AFS file server fails to extend a
3007         server lock that was required to assert the lock.  Before
3008         marking the lock as lost, the cache manager checks if the file
3009         has changed on the server.  If the file has not changed, then
3010         the cache manager will attempt to obtain a new server lock
3011         that is sufficient to assert the client side locks for the
3012         file.  If any of these fail, the lock is marked as LOST.
3013         Otherwise, it is left as ACTIVE.
3014
3015       1.2 ACTIVE->DELETED: Lock is released.
3016
3017    2. WAITLOCK: A lock is in a WAITLOCK state if the cache manager
3018       grants the lock but the lock is yet to be asserted with the AFS
3019       file server.  Once the file server grants the lock, the state
3020       will transition to an ACTIVE lock.
3021
3022       2.1 WAITLOCK->ACTIVE: The server granted the lock.
3023
3024       2.2 WAITLOCK->DELETED: Lock is abandoned, or timed out during
3025         waiting.
3026
3027       2.3 WAITLOCK->LOST: One or more locks from this client were
3028         marked as LOST.  No further locks will be granted to this
3029         client until all lost locks are removed.
3030
3031    3. WAITUNLOCK: A lock is in a WAITUNLOCK state if the cache manager
3032       receives a request for a lock that conflicts with an existing
3033       ACTIVE or WAITLOCK lock.  The lock will be placed in the queue
3034       and will be granted at such time the conflicting locks are
3035       removed, at which point the state will transition to either
3036       WAITLOCK or ACTIVE.
3037
3038       3.1 WAITUNLOCK->ACTIVE: The conflicting lock was removed.  The
3039         current serverLock is sufficient to assert this lock, or a
3040         sufficient serverLock is obtained.
3041
3042       3.2 WAITUNLOCK->WAITLOCK: The conflicting lock was removed,
3043         however the required serverLock is yet to be asserted with the
3044         server.
3045
3046       3.3 WAITUNLOCK->DELETED: The lock is abandoned, timed out or
3047         released.
3048
3049       3.5 WAITUNLOCK->LOST: One or more locks from this client were
3050         marked as LOST.  No further locks will be granted to this
3051         client until all lost locks are removed.
3052
3053    4. LOST: A lock L is LOST if the server lock that was required to
3054       assert the lock could not be obtained or if it could not be
3055       extended, or if other locks by the same client were LOST.
3056       Essentially, once a lock is LOST, the contract between the cache
3057       manager and that specific client is no longer valid.
3058
3059       The cache manager rechecks the server lock once every minute and
3060       extends it as appropriate.  If this is not done for 5 minutes,
3061       the AFS file server will release the lock (the 5 minute timeout
3062       is based on current file server code and is fairly arbitrary).
3063       Once released, the lock cannot be re-obtained without verifying
3064       that the contents of the file hasn't been modified since the
3065       time the lock was released.  Re-obtaining the lock without
3066       verifying this may lead to data corruption.  If the lock can not
3067       be obtained safely, then all active locks for the cm_scache_t
3068       are marked as LOST.
3069
3070       4.1 LOST->DELETED: The lock is released.
3071
3072    5. DELETED: The lock is no longer relevant.  Eventually, it will
3073       get removed from the cm_scache_t. In the meantime, it will be
3074       treated as if it does not exist.
3075
3076       5.1 DELETED->not exist: The lock is removed from the
3077         cm_scache_t.
3078
3079    The following are classifications of locks based on their state.
3080
3081    6* A lock L is ACCEPTED if it is ACTIVE or WAITLOCK.  These locks
3082       have been accepted by the cache manager, but may or may not have
3083       been granted back to the client.
3084
3085    7* A lock L is QUEUED if it is ACTIVE, WAITLOCK or WAITUNLOCK.
3086
3087    8* A lock L is WAITING if it is WAITLOCK or WAITUNLOCK.
3088
3089    Lock operation:
3090
3091    A client C can READ range (Offset,+Length) of a file represented by
3092    cm_scache_t S iff (1):
3093
3094    1. for all _a_ in (Offset,+Length), all of the following is true:
3095
3096        1.1 For each ACTIVE lock L in S->fileLocks such that _a_ in
3097          (L->LOffset,+L->LLength); L->key == Key(C) OR L->LockType is
3098          shared.
3099
3100        1.2 For each LOST lock L in S->fileLocks such that _a_ in
3101          (L->LOffset,+L->LLength); L->LockType is shared AND L->key !=
3102          Key(C)
3103
3104        (When locks are lost on an cm_scache_t, all locks are lost.  By
3105        4.2 (below), if there is an exclusive LOST lock, then there
3106        can't be any overlapping ACTIVE locks.)
3107
3108    A client C can WRITE range (Offset,+Length) of cm_scache_t S iff (2):
3109
3110    2. for all _a_ in (Offset,+Length), one of the following is true:
3111
3112        2.1 Byte _a_ of S is unowned (as specified in 1.1) AND there
3113          does not exist a LOST lock L such that _a_ in
3114          (L->LOffset,+L->LLength).
3115
3116        2.2 Byte _a_ of S is owned by C under lock L (as specified in
3117          1.2) AND L->LockType is exclusive.
3118
3119    A client C can OBTAIN a lock L on cm_scache_t S iff (both 3 and 4):
3120
3121    3. for all _a_ in (L->LOffset,+L->LLength), ALL of the following is
3122       true:
3123
3124        3.1 If L->LockType is exclusive then there does NOT exist a
3125          ACCEPTED lock M in S->fileLocks such that _a_ in
3126          (M->LOffset,+M->LLength).
3127
3128          (If we count all QUEUED locks then we hit cases such as
3129          cascading waiting locks where the locks later on in the queue
3130          can be granted without compromising file integrity.  On the
3131          other hand if only ACCEPTED locks are considered, then locks
3132          that were received earlier may end up waiting for locks that
3133          were received later to be unlocked. The choice of ACCEPTED
3134          locks was made to mimic the Windows byte range lock
3135          semantics.)
3136
3137        3.2 If L->LockType is shared then for each ACCEPTED lock M in
3138          S->fileLocks, if _a_ in (M->LOffset,+M->LLength) then
3139          M->LockType is shared.
3140
3141    4. For all LOST locks M in S->fileLocks, ALL of the following are true:
3142
3143        4.1 M->key != Key(C)
3144
3145        4.2 If M->LockType is exclusive, then (L->LOffset,+L->LLength)
3146          and (M->LOffset,+M->LLength) do not intersect.
3147
3148          (Note: If a client loses a lock, it loses all locks.
3149          Subsequently, it will not be allowed to obtain any more locks
3150          until all existing LOST locks that belong to the client are
3151          released.  Once all locks are released by a single client,
3152          there exists no further contract between the client and AFS
3153          about the contents of the file, hence the client can then
3154          proceed to obtain new locks and establish a new contract.
3155
3156          This doesn't quite work as you think it should, because most
3157          applications aren't built to deal with losing locks they
3158          thought they once had.  For now, we don't have a good
3159          solution to lost locks.
3160
3161          Also, for consistency reasons, we have to hold off on
3162          granting locks that overlap exclusive LOST locks.)
3163
3164    A client C can only unlock locks L in S->fileLocks which have
3165    L->key == Key(C).
3166
3167    The representation and invariants are as follows:
3168
3169    - Each cm_scache_t structure keeps:
3170
3171        - A queue of byte-range locks (cm_scache_t::fileLocks) which
3172          are of type cm_file_lock_t.
3173
3174        - A record of the highest server-side lock that has been
3175          obtained for this object (cm_scache_t::serverLock), which is
3176          one of (-1), LockRead, LockWrite.
3177
3178        - A count of ACCEPTED exclusive and shared locks that are in the
3179          queue (cm_scache_t::sharedLocks and
3180          cm_scache_t::exclusiveLocks)
3181
3182    - Each cm_file_lock_t structure keeps:
3183
3184        - The type of lock (cm_file_lock_t::LockType)
3185
3186        - The key associated with the lock (cm_file_lock_t::key)
3187
3188        - The offset and length of the lock (cm_file_lock_t::LOffset
3189          and cm_file_lock_t::LLength)
3190
3191        - The state of the lock.
3192
3193        - Time of issuance or last successful extension
3194
3195    Semantic invariants:
3196
3197        I1. The number of ACCEPTED locks in S->fileLocks are
3198            (S->sharedLocks + S->exclusiveLocks)
3199
3200    External invariants:
3201
3202        I3. S->serverLock is the lock that we have asserted with the
3203            AFS file server for this cm_scache_t.
3204
3205        I4. S->serverLock == LockRead iff there is at least one ACTIVE
3206            shared lock, but no ACTIVE exclusive locks.
3207
3208        I5. S->serverLock == LockWrite iff there is at least one ACTIVE
3209            exclusive lock.
3210
3211        I6. If L is a LOST lock, then for each lock M in S->fileLocks,
3212            M->key == L->key IMPLIES M is LOST or DELETED.
3213
3214    --asanka
3215  */
3216
3217 #define IS_LOCK_ACTIVE(lockp)     (((lockp)->flags & (CM_FILELOCK_FLAG_DELETED|CM_FILELOCK_FLAG_WAITLOCK|CM_FILELOCK_FLAG_WAITUNLOCK|CM_FILELOCK_FLAG_LOST)) == 0)
3218
3219 #define IS_LOCK_WAITLOCK(lockp)   (((lockp)->flags & (CM_FILELOCK_FLAG_DELETED|CM_FILELOCK_FLAG_WAITLOCK|CM_FILELOCK_FLAG_WAITUNLOCK|CM_FILELOCK_FLAG_LOST)) == CM_FILELOCK_FLAG_WAITLOCK)
3220
3221 #define IS_LOCK_WAITUNLOCK(lockp) (((lockp)->flags & (CM_FILELOCK_FLAG_DELETED|CM_FILELOCK_FLAG_WAITLOCK|CM_FILELOCK_FLAG_WAITUNLOCK|CM_FILELOCK_FLAG_LOST)) == CM_FILELOCK_FLAG_WAITUNLOCK)
3222
3223 #define IS_LOCK_LOST(lockp)       (((lockp)->flags & (CM_FILELOCK_FLAG_DELETED|CM_FILELOCK_FLAG_LOST)) == CM_FILELOCK_FLAG_LOST)
3224
3225 #define IS_LOCK_DELETED(lockp)    (((lockp)->flags & CM_FILELOCK_FLAG_DELETED) == CM_FILELOCK_FLAG_DELETED)
3226
3227 /* unsafe */
3228 #define IS_LOCK_ACCEPTED(lockp)   (IS_LOCK_ACTIVE(lockp) || IS_LOCK_WAITLOCK(lockp))
3229
3230 /* unsafe */
3231 #define IS_LOCK_CLIENTONLY(lockp) ((((lockp)->scp->flags & CM_SCACHEFLAG_RO) == CM_SCACHEFLAG_RO) || (((lockp)->flags & CM_FILELOCK_FLAG_CLIENTONLY) == CM_FILELOCK_FLAG_CLIENTONLY))
3232
3233 /* unsafe */
3234 #define INTERSECT_RANGE(r1,r2) (((r2).offset+(r2).length) > (r1).offset && ((r1).offset +(r1).length) > (r2).offset)
3235
3236 /* unsafe */
3237 #define CONTAINS_RANGE(r1,r2) (((r2).offset+(r2).length) <= ((r1).offset+(r1).length) && (r1).offset <= (r2).offset)
3238
3239 #if defined(VICED_CAPABILITY_USE_BYTE_RANGE_LOCKS) && !defined(LOCK_TESTING)
3240 #define SCP_SUPPORTS_BRLOCKS(scp) ((scp)->cbServerp && ((scp)->cbServerp->capabilities & VICED_CAPABILITY_USE_BYTE_RANGE_LOCKS))
3241 #else
3242 #define SCP_SUPPORTS_BRLOCKS(scp) (1)
3243 #endif
3244
3245 #define SERVERLOCKS_ENABLED(scp) (!((scp)->flags & CM_SCACHEFLAG_RO) && cm_enableServerLocks && SCP_SUPPORTS_BRLOCKS(scp))
3246
3247 static void cm_LockRangeSubtract(cm_range_t * pos, const cm_range_t * neg)
3248 {
3249     afs_int64 int_begin;
3250     afs_int64 int_end;
3251
3252     int_begin = MAX(pos->offset, neg->offset);
3253     int_end = MIN(pos->offset+pos->length, neg->offset+neg->length);
3254
3255     if (int_begin < int_end) {
3256         if (int_begin == pos->offset) {
3257             pos->length = pos->offset + pos->length - int_end;
3258             pos->offset = int_end;
3259         } else if (int_end == pos->offset + pos->length) {
3260             pos->length = int_begin - pos->offset;
3261         }
3262
3263         /* We only subtract ranges if the resulting range is
3264            contiguous.  If we try to support non-contigous ranges, we
3265            aren't actually improving performance. */
3266     }
3267 }
3268
3269 /* Called with scp->mx held.  Returns 0 if all is clear to read the
3270    specified range by the client identified by key.
3271  */
3272 long cm_LockCheckRead(cm_scache_t *scp, 
3273                       LARGE_INTEGER LOffset, 
3274                       LARGE_INTEGER LLength, 
3275                       cm_key_t key)
3276 {
3277 #ifndef ADVISORY_LOCKS
3278
3279     cm_file_lock_t *fileLock;
3280     osi_queue_t *q;
3281     long code = 0;
3282     cm_range_t range;
3283     int substract_ranges = FALSE;
3284
3285     range.offset = LOffset.QuadPart;
3286     range.length = LLength.QuadPart;
3287
3288     /*
3289
3290      1. for all _a_ in (Offset,+Length), all of the following is true:
3291
3292        1.1 For each ACTIVE lock L in S->fileLocks such that _a_ in
3293          (L->LOffset,+L->LLength); L->key == Key(C) OR L->LockType is
3294          shared.
3295
3296        1.2 For each LOST lock L in S->fileLocks such that _a_ in
3297          (L->LOffset,+L->LLength); L->LockType is shared AND L->key !=
3298          Key(C)
3299
3300     */
3301
3302     lock_ObtainRead(&cm_scacheLock);
3303
3304     for (q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
3305         fileLock = 
3306             (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
3307
3308         if (INTERSECT_RANGE(range, fileLock->range)) {
3309             if (IS_LOCK_ACTIVE(fileLock)) {
3310                 if (fileLock->key == key) {
3311
3312                     /* If there is an active lock for this client, it
3313                        is safe to substract ranges.*/
3314                     cm_LockRangeSubtract(&range, &fileLock->range);
3315                     substract_ranges = TRUE;
3316                 } else {
3317                     if (fileLock->lockType != LockRead) {
3318                         code = CM_ERROR_LOCK_CONFLICT;
3319                         break;
3320                     }
3321
3322                     /* even if the entire range is locked for reading,
3323                        we still can't grant the lock at this point
3324                        because the client may have lost locks. That
3325                        is, unless we have already seen an active lock
3326                        belonging to the client, in which case there
3327                        can't be any lost locks for this client. */
3328                     if (substract_ranges)
3329                         cm_LockRangeSubtract(&range, &fileLock->range);
3330                 }
3331             } else if (IS_LOCK_LOST(fileLock) &&
3332                       (fileLock->key == key || fileLock->lockType == LockWrite)) {
3333                 code = CM_ERROR_BADFD;
3334                 break;
3335             }
3336         }
3337     }
3338
3339     lock_ReleaseRead(&cm_scacheLock);
3340
3341     osi_Log4(afsd_logp, "cm_LockCheckRead scp 0x%x offset %d length %d code 0x%x",
3342               scp, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart, code);
3343
3344     return code;
3345
3346 #else
3347
3348     return 0;
3349
3350 #endif
3351 }
3352
3353 /* Called with scp->mx held.  Returns 0 if all is clear to write the
3354    specified range by the client identified by key.
3355  */
3356 long cm_LockCheckWrite(cm_scache_t *scp,
3357                        LARGE_INTEGER LOffset,
3358                        LARGE_INTEGER LLength,
3359                        cm_key_t key)
3360 {
3361 #ifndef ADVISORY_LOCKS
3362
3363     cm_file_lock_t *fileLock;
3364     osi_queue_t *q;
3365     long code = 0;
3366     cm_range_t range;
3367
3368     range.offset = LOffset.QuadPart;
3369     range.length = LLength.QuadPart;
3370
3371     /*
3372    A client C can WRITE range (Offset,+Length) of cm_scache_t S iff (2):
3373
3374    2. for all _a_ in (Offset,+Length), one of the following is true:
3375
3376        2.1 Byte _a_ of S is unowned AND there does not exist a LOST
3377          lock L such that _a_ in (L->LOffset,+L->LLength).
3378
3379        2.2 Byte _a_ of S is owned by C under lock L AND L->LockType is
3380          exclusive.
3381     */
3382
3383     lock_ObtainRead(&cm_scacheLock);
3384
3385     for (q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
3386         fileLock = 
3387             (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
3388
3389         if (INTERSECT_RANGE(range, fileLock->range)) {
3390             if (IS_LOCK_ACTIVE(fileLock)) {
3391                 if (fileLock->key == key) {
3392                     if (fileLock->lockType == LockWrite) {
3393
3394                         /* if there is an active lock for this client, it
3395                            is safe to substract ranges */
3396                         cm_LockRangeSubtract(&range, &fileLock->range);
3397                     } else {
3398                         code = CM_ERROR_LOCK_CONFLICT;
3399                         break;
3400                     }
3401                 } else {
3402                     code = CM_ERROR_LOCK_CONFLICT;
3403                     break;
3404                 }
3405             } else if (IS_LOCK_LOST(fileLock)) {
3406                 code = CM_ERROR_BADFD;
3407                 break;
3408             }
3409         }
3410     }
3411
3412     lock_ReleaseRead(&cm_scacheLock);
3413
3414     osi_Log4(afsd_logp, "cm_LockCheckWrite scp 0x%x offset %d length %d code 0x%x",
3415               scp, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart, code);
3416
3417     return code;
3418
3419 #else
3420
3421     return 0;
3422
3423 #endif
3424 }
3425
3426 /* Forward dcl. */
3427 static void cm_LockMarkSCacheLost(cm_scache_t * scp);
3428
3429 /* Called with cm_scacheLock write locked */
3430 static cm_file_lock_t * cm_GetFileLock(void) {
3431     cm_file_lock_t * l;
3432
3433     l = (cm_file_lock_t *) cm_freeFileLocks;
3434     if (l) {
3435         osi_QRemove(&cm_freeFileLocks, &l->q);
3436     } else {
3437         l = malloc(sizeof(cm_file_lock_t));
3438         osi_assert(l);
3439     }
3440
3441     memset(l, 0, sizeof(cm_file_lock_t));
3442
3443     return l;
3444 }
3445
3446 /* Called with cm_scacheLock write locked */
3447 static void cm_PutFileLock(cm_file_lock_t *l) {
3448     osi_QAdd(&cm_freeFileLocks, &l->q);
3449 }
3450
3451 /* called with scp->mx held.  May release it during processing, but
3452    leaves it held on exit. */
3453 long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
3454                    cm_req_t * reqp) {
3455     long code = 0;
3456     AFSFid tfid;
3457     cm_fid_t cfid;
3458     cm_conn_t * connp;
3459     struct rx_connection * callp;
3460     AFSVolSync volSync;
3461
3462     tfid.Volume = scp->fid.volume;
3463     tfid.Vnode = scp->fid.vnode;
3464     tfid.Unique = scp->fid.unique;
3465     cfid = scp->fid;
3466
3467     osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
3468
3469     lock_ReleaseMutex(&scp->mx);
3470
3471     do {
3472         code = cm_Conn(&cfid, userp, reqp, &connp);
3473         if (code) 
3474             break;
3475
3476         callp = cm_GetRxConn(connp);
3477         code = RXAFS_SetLock(callp, &tfid, lockType,
3478                              &volSync);
3479         rx_PutConnection(callp);
3480
3481     } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
3482                         NULL, NULL, code));
3483
3484     code = cm_MapRPCError(code, reqp);
3485     if (code) {
3486         osi_Log1(afsd_logp, "CALL SetLock FAILURE, code 0x%x", code);
3487     } else {
3488         osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
3489     }
3490
3491     lock_ObtainMutex(&scp->mx);
3492
3493     return code;
3494 }
3495
3496 /* called with scp->mx held.  Releases it during processing */
3497 long cm_IntReleaseLock(cm_scache_t * scp, cm_user_t * userp,
3498                        cm_req_t * reqp) {
3499     long code = 0;
3500     AFSFid tfid;
3501     cm_fid_t cfid;
3502     cm_conn_t * connp;
3503     struct rx_connection * callp;
3504     AFSVolSync volSync;
3505
3506     tfid.Volume = scp->fid.volume;
3507     tfid.Vnode = scp->fid.vnode;
3508     tfid.Unique = scp->fid.unique;
3509     cfid = scp->fid;
3510
3511     lock_ReleaseMutex(&scp->mx);
3512
3513     osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
3514
3515     do {
3516         code = cm_Conn(&cfid, userp, reqp, &connp);
3517         if (code) 
3518             break;
3519
3520         callp = cm_GetRxConn(connp);
3521         code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
3522         rx_PutConnection(callp);
3523
3524     } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
3525                         NULL, NULL, code));
3526     code = cm_MapRPCError(code, reqp);
3527     if (code)
3528         osi_Log1(afsd_logp,
3529                  "CALL ReleaseLock FAILURE, code 0x%x", code);
3530     else
3531         osi_Log0(afsd_logp,
3532                  "CALL ReleaseLock SUCCESS");
3533         
3534     lock_ObtainMutex(&scp->mx);
3535
3536     return code;
3537 }
3538
3539 /* called with scp->mx held.  May release it during processing, but
3540    will exit with lock held.
3541
3542    This will return:
3543
3544    - 0 if the user has permission to get the specified lock for the scp
3545
3546    - CM_ERROR_NOACCESS if not
3547
3548    Any other error from cm_SyncOp will be sent down untranslated.
3549 */
3550 long cm_LockCheckPerms(cm_scache_t * scp,
3551                        int lock_type,
3552                        cm_user_t * userp,
3553                        cm_req_t * reqp)
3554 {
3555     long rights = 0;
3556     long code = 0;
3557
3558     /* lock permissions are slightly tricky because of the 'i' bit.
3559        If the user has PRSFS_LOCK, she can read-lock the file.  If the
3560        user has PRSFS_WRITE, she can write-lock the file.  However, if
3561        the user has PRSFS_INSERT, then she can write-lock new files,
3562        but not old ones.  Since we don't have information about
3563        whether a file is new or not, we assume that if the user owns
3564        the scp, then she has the permissions that are granted by
3565        PRSFS_INSERT. */
3566
3567     osi_Log3(afsd_logp, "cm_LockCheckPerms for scp[0x%p] type[%d] user[0x%p]",
3568              scp, lock_type, userp);
3569
3570     if (lock_type == LockRead)
3571         rights |= PRSFS_LOCK;
3572     else if (lock_type == LockWrite)
3573         rights |= PRSFS_WRITE;
3574     else {
3575         /* hmmkay */
3576         osi_assert(FALSE);
3577         return 0;
3578     }
3579
3580     code = cm_SyncOp(scp, NULL, userp, reqp, rights,
3581                      CM_SCACHESYNC_GETSTATUS |
3582                      CM_SCACHESYNC_NEEDCALLBACK);
3583
3584     if (code == CM_ERROR_NOACCESS &&
3585         lock_type == LockWrite &&
3586         scp->creator == userp) {
3587         /* check for PRSFS_INSERT. */
3588
3589         code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_INSERT,
3590                          CM_SCACHESYNC_GETSTATUS |
3591                          CM_SCACHESYNC_NEEDCALLBACK);
3592
3593         if (code == CM_ERROR_NOACCESS)
3594             osi_Log0(afsd_logp, "cm_LockCheckPerms user is creator but has no INSERT bits for scp");
3595     }
3596
3597     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3598
3599     osi_Log1(afsd_logp, "cm_LockCheckPerms returning code %d", code);
3600
3601     return code;
3602 }
3603
3604 /* called with scp->mx held */
3605 long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
3606              LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
3607              cm_key_t key,
3608              int allowWait, cm_user_t *userp, cm_req_t *reqp,
3609              cm_file_lock_t **lockpp)
3610 {
3611     long code = 0;
3612     int Which = ((sLockType & LOCKING_ANDX_SHARED_LOCK) ? LockRead : LockWrite);
3613     cm_file_lock_t *fileLock;
3614     osi_queue_t *q;
3615     cm_range_t range;
3616     int wait_unlock = FALSE;
3617     int force_client_lock = FALSE;
3618
3619     osi_Log4(afsd_logp, "cm_Lock scp 0x%x type 0x%x offset %d length %d",
3620              scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
3621     osi_Log3(afsd_logp, "... allowWait %d key 0x%x:%x", allowWait, 
3622              (unsigned long)(key >> 32), (unsigned long)(key & 0xffffffff));
3623
3624     /*
3625    A client C can OBTAIN a lock L on cm_scache_t S iff (both 3 and 4):
3626
3627    3. for all _a_ in (L->LOffset,+L->LLength), ALL of the following is
3628       true:
3629
3630        3.1 If L->LockType is exclusive then there does NOT exist a
3631          ACCEPTED lock M in S->fileLocks such that _a_ in
3632          (M->LOffset,+M->LLength).
3633
3634        3.2 If L->LockType is shared then for each ACCEPTED lock M in
3635          S->fileLocks, if _a_ in (M->LOffset,+M->LLength) then
3636          M->LockType is shared.
3637
3638    4. For all LOST locks M in S->fileLocks, ALL of the following are true:
3639
3640        4.1 M->key != Key(C)
3641
3642        4.2 If M->LockType is exclusive, then (L->LOffset,+L->LLength)
3643          and (M->LOffset,+M->LLength) do not intersect.
3644     */
3645
3646     range.offset = LOffset.QuadPart;
3647     range.length = LLength.QuadPart;
3648
3649     lock_ObtainRead(&cm_scacheLock);
3650
3651     for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
3652         fileLock =
3653             (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
3654
3655         if (IS_LOCK_LOST(fileLock)) {
3656             if (fileLock->key == key) {
3657                 code = CM_ERROR_BADFD;
3658                 break;
3659             } else if (fileLock->lockType == LockWrite && INTERSECT_RANGE(range, fileLock->range)) {
3660                 code = CM_ERROR_WOULDBLOCK;
3661                 wait_unlock = TRUE;
3662                 break;
3663             }
3664         }
3665
3666         /* we don't need to check for deleted locks here since deleted
3667            locks are dequeued from scp->fileLocks */
3668         if (IS_LOCK_ACCEPTED(fileLock) &&
3669            INTERSECT_RANGE(range, fileLock->range)) {
3670
3671             if ((sLockType & LOCKING_ANDX_SHARED_LOCK) == 0 ||
3672                 fileLock->lockType != LockRead) {
3673                 wait_unlock = TRUE;
3674                 code = CM_ERROR_WOULDBLOCK;
3675                 break;
3676             }
3677         }
3678     }
3679
3680     lock_ReleaseRead(&cm_scacheLock);
3681
3682     if (code == 0 && SERVERLOCKS_ENABLED(scp)) {
3683         if (Which == scp->serverLock ||
3684            (Which == LockRead && scp->serverLock == LockWrite)) {
3685
3686             /* we already have the lock we need */
3687             osi_Log3(afsd_logp, "   we already have the correct lock. exclusives[%d], shared[%d], serverLock[%d]", 
3688                      scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
3689
3690             code = cm_LockCheckPerms(scp, Which, userp, reqp);
3691
3692             /* special case: if we don't have permission to read-lock
3693                the file, then we force a clientside lock.  This is to
3694                compensate for applications that obtain a read-lock for
3695                reading files off of directories that don't grant
3696                read-locks to the user. */
3697             if (code == CM_ERROR_NOACCESS && Which == LockRead) {
3698                 osi_Log0(afsd_logp, "   User has no read-lock perms. Forcing client-side lock");
3699                 force_client_lock = TRUE;
3700             }
3701
3702         } else if ((scp->exclusiveLocks > 0) ||
3703                    (scp->sharedLocks > 0 && scp->serverLock != LockRead)) {
3704
3705             /* We are already waiting for some other lock.  We should
3706                wait for the daemon to catch up instead of generating a
3707                flood of SetLock calls. */
3708             osi_Log3(afsd_logp, "   already waiting for other lock. exclusives[%d], shared[%d], serverLock[%d]",
3709                      scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
3710
3711             /* see if we have permission to create the lock in the
3712                first place. */
3713             code = cm_LockCheckPerms(scp, Which, userp, reqp);
3714             if (code == 0)
3715                 code = CM_ERROR_WOULDBLOCK;
3716             else if (code == CM_ERROR_NOACCESS && Which == LockRead) {
3717                 osi_Log0(afsd_logp, "   User has no read-lock perms.  Forcing client-side lock");
3718                 force_client_lock = TRUE;
3719             }
3720
3721             /* leave any other codes as-is */
3722
3723         } else {
3724             int newLock;
3725             int check_data_version = FALSE;
3726
3727             /* first check if we have permission to elevate or obtain
3728                the lock. */
3729             code = cm_LockCheckPerms(scp, Which, userp, reqp);
3730             if (code) {
3731                 if (code == CM_ERROR_NOACCESS && Which == LockRead) {
3732                     osi_Log0(afsd_logp, "   User has no read-lock perms.  Forcing client-side lock");
3733                     force_client_lock = TRUE;
3734                 }
3735                 goto check_code;
3736             }
3737
3738             if (scp->serverLock == LockRead && Which == LockWrite) {
3739
3740                 /* We want to escalate the lock to a LockWrite.
3741                    Unfortunately that's not really possible without
3742                    letting go of the current lock.  But for now we do
3743                    it anyway. */
3744
3745                 osi_Log0(afsd_logp,
3746                          "   attempting to UPGRADE from LockRead to LockWrite.");
3747                 osi_Log1(afsd_logp,
3748                          "   dataVersion on scp: %d", scp->dataVersion);
3749
3750                 /* we assume at this point (because scp->serverLock
3751                    was valid) that we had a valid server lock. */
3752                 scp->lockDataVersion = scp->dataVersion;
3753                 check_data_version = TRUE;
3754         
3755                 code = cm_IntReleaseLock(scp, userp, reqp);
3756
3757                 if (code) {
3758                     /* We couldn't release the lock */
3759                     goto check_code;
3760                 } else {
3761                     scp->serverLock = -1;
3762                 }
3763             }
3764
3765             /* We need to obtain a server lock of type Which in order
3766                to assert this file lock */
3767 #ifndef AGGRESSIVE_LOCKS
3768             newLock = Which;
3769 #else
3770             newLock = LockWrite;
3771 #endif
3772             code = cm_IntSetLock(scp, userp, newLock, reqp);
3773
3774             if (code == CM_ERROR_WOULDBLOCK && newLock != Which) {
3775                 /* we wanted LockRead.  We tried LockWrite. Now try
3776                    LockRead again */
3777                 newLock = Which;
3778
3779                 /* am I sane? */
3780                 osi_assert(newLock == LockRead);
3781
3782                 code = cm_IntSetLock(scp, userp, newLock, reqp);
3783             }
3784
3785             if (code == 0 && check_data_version &&
3786                scp->dataVersion != scp->lockDataVersion) {
3787                 /* We lost a race.  Although we successfully obtained
3788                    a lock, someone modified the file in between.  The
3789                    locks have all been technically lost. */
3790
3791                 osi_Log0(afsd_logp,
3792                          "  Data version mismatch while upgrading lock.");
3793                 osi_Log2(afsd_logp,
3794                          "  Data versions before=%d, after=%d",
3795                          scp->lockDataVersion,
3796                          scp->dataVersion);
3797                 osi_Log1(afsd_logp,
3798                          "  Releasing stale lock for scp 0x%x", scp);
3799
3800                 code = cm_IntReleaseLock(scp, userp, reqp);
3801
3802                 scp->serverLock = -1;
3803
3804                 code = CM_ERROR_INVAL;
3805             } else if (code == 0) {
3806                 scp->serverLock = newLock;
3807                 scp->lockDataVersion = scp->dataVersion;
3808             }
3809
3810             if (code != 0 &&
3811                 (scp->sharedLocks > 0 || scp->exclusiveLocks > 0) &&
3812                     scp->serverLock == -1) {
3813                     /* Oops. We lost the lock. */
3814                     cm_LockMarkSCacheLost(scp);
3815                 }
3816             }
3817     } else if (code == 0) {     /* server locks not enabled */
3818         osi_Log0(afsd_logp,
3819                  "  Skipping server lock for scp");
3820     }
3821
3822  check_code:
3823
3824     if (code != 0 && !force_client_lock) {
3825         /* Special case error translations
3826
3827            Applications don't expect certain errors from a
3828            LockFile/UnlockFile call.  We need to translate some error
3829            code to codes that apps expect and handle. */
3830
3831         /* We shouldn't actually need to handle this case since we
3832            simulate locks for RO scps anyway. */
3833         if (code == CM_ERROR_READONLY) {
3834             osi_Log0(afsd_logp, "   Reinterpreting CM_ERROR_READONLY as CM_ERROR_NOACCESS");
3835             code = CM_ERROR_NOACCESS;
3836         }
3837     }
3838
3839     if (code == 0 || (code == CM_ERROR_WOULDBLOCK && allowWait) ||
3840         force_client_lock) {
3841
3842         /* clear the error if we are forcing a client lock, so we
3843            don't get confused later. */
3844         if (force_client_lock && code != CM_ERROR_WOULDBLOCK)
3845             code = 0;
3846
3847         lock_ObtainWrite(&cm_scacheLock);
3848         fileLock = cm_GetFileLock();
3849         lock_ReleaseWrite(&cm_scacheLock);
3850 #ifdef DEBUG
3851         fileLock->fid = scp->fid;
3852 #endif
3853         fileLock->key = key;
3854         fileLock->lockType = Which;
3855         cm_HoldUser(userp);
3856         fileLock->userp = userp;
3857         fileLock->range = range;
3858         fileLock->flags = (code == 0 ? 0 : 
3859                            ((wait_unlock)?
3860                             CM_FILELOCK_FLAG_WAITUNLOCK :
3861                             CM_FILELOCK_FLAG_WAITLOCK));
3862
3863         if (force_client_lock || !SERVERLOCKS_ENABLED(scp))
3864             fileLock->flags |= CM_FILELOCK_FLAG_CLIENTONLY;
3865
3866         fileLock->lastUpdate = (code == 0 && !force_client_lock) ? time(NULL) : 0;
3867
3868         lock_ObtainWrite(&cm_scacheLock);
3869         osi_QAddT(&scp->fileLocksH, &scp->fileLocksT, &fileLock->fileq);
3870         cm_HoldSCacheNoLock(scp);
3871         fileLock->scp = scp;
3872         osi_QAdd(&cm_allFileLocks, &fileLock->q);
3873         lock_ReleaseWrite(&cm_scacheLock);
3874
3875         if (code != 0) {
3876             *lockpp = fileLock;
3877         }
3878
3879         if (IS_LOCK_CLIENTONLY(fileLock)) {
3880             scp->clientLocks++;
3881         } else if (IS_LOCK_ACCEPTED(fileLock)) {
3882             if (Which == LockRead)
3883                 scp->sharedLocks++;
3884             else
3885                 scp->exclusiveLocks++;
3886         }
3887
3888         osi_Log3(afsd_logp,
3889                  "cm_Lock Lock added 0x%p flags 0x%x to scp [0x%p]",
3890                  fileLock, fileLock->flags, scp);
3891         osi_Log4(afsd_logp,
3892                  "   exclusives[%d] shared[%d] client[%d] serverLock[%d]",
3893                  scp->exclusiveLocks, scp->sharedLocks, scp->clientLocks,
3894                  (int)(signed char) scp->serverLock);
3895     } else {
3896         osi_Log1(afsd_logp,
3897                  "cm_Lock Rejecting lock (code = 0x%x)", code);
3898     }
3899
3900     return code;
3901 }
3902
3903 static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags);
3904
3905 /* Called with scp->mx held */
3906 long cm_UnlockByKey(cm_scache_t * scp,
3907                     cm_key_t key,
3908                     int flags,
3909                     cm_user_t * userp,
3910                      cm_req_t * reqp)
3911 {
3912     long code = 0;
3913     cm_file_lock_t *fileLock;
3914     osi_queue_t *q, *qn;
3915     int n_unlocks = 0;
3916
3917     osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key 0x%x:%x flags=0x%x",
3918              scp,
3919              (unsigned long)(key >> 32),
3920              (unsigned long)(key & 0xffffffff),
3921              flags);
3922
3923     lock_ObtainWrite(&cm_scacheLock);
3924
3925     for (q = scp->fileLocksH; q; q = qn) {
3926         qn = osi_QNext(q);
3927
3928         fileLock = (cm_file_lock_t *)
3929             ((char *) q - offsetof(cm_file_lock_t, fileq));
3930
3931 #ifdef DEBUG
3932         osi_Log4(afsd_logp, "   Checking lock[0x%x] range[%d,+%d] type[%d]",
3933                  fileLock,
3934                  (unsigned long) fileLock->range.offset,
3935                  (unsigned long) fileLock->range.length,
3936                 fileLock->lockType);
3937         osi_Log3(afsd_logp, "     key[0x%x:%x] flags[0x%x]",
3938                  (unsigned long)(fileLock->key >> 32),
3939                  (unsigned long)(fileLock->key & 0xffffffff),
3940                  fileLock->flags);
3941
3942         if (cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
3943             osi_Log0(afsd_logp, "!!fileLock->fid != scp->fid");
3944             osi_Log4(afsd_logp, "  fileLock->fid(cell=[%d], volume=[%d], vnode=[%d], unique=[%d]",
3945                      fileLock->fid.cell,
3946                      fileLock->fid.volume,
3947                      fileLock->fid.vnode,
3948                      fileLock->fid.unique);
3949             osi_Log4(afsd_logp, "  scp->fid(cell=[%d], volume=[%d], vnode=[%d], unique=[%d]",
3950                      fileLock->scp->fid.cell,
3951                      fileLock->scp->fid.volume,
3952                      fileLock->scp->fid.vnode,
3953                      fileLock->scp->fid.unique);
3954             osi_assert(FALSE);
3955         }
3956 #endif
3957
3958         if (!IS_LOCK_DELETED(fileLock) &&
3959             cm_KeyEquals(fileLock->key, key, flags)) {
3960             osi_Log3(afsd_logp, "...Unlock range [%d,+%d] type %d",
3961                     fileLock->range.offset,
3962                     fileLock->range.length,
3963                     fileLock->lockType);
3964
3965             if (scp->fileLocksT == q)
3966                 scp->fileLocksT = osi_QPrev(q);
3967             osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
3968
3969             if (IS_LOCK_CLIENTONLY(fileLock)) {
3970                 scp->clientLocks--;
3971             } else if (IS_LOCK_ACCEPTED(fileLock)) {
3972                 if (fileLock->lockType == LockRead)
3973                     scp->sharedLocks--;
3974                 else
3975                     scp->exclusiveLocks--;
3976             }
3977
3978             fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
3979
3980             cm_ReleaseUser(fileLock->userp);
3981             cm_ReleaseSCacheNoLock(scp);
3982
3983             fileLock->userp = NULL;
3984             fileLock->scp = NULL;
3985
3986             n_unlocks++;
3987         }
3988     }
3989
3990     lock_ReleaseWrite(&cm_scacheLock);
3991
3992     if (n_unlocks == 0) {
3993         osi_Log0(afsd_logp, "cm_UnlockByKey no locks found");
3994         osi_Log3(afsd_logp, "   Leaving scp with exclusives[%d], shared[%d], serverLock[%d]",
3995                  scp->exclusiveLocks, scp->sharedLocks, (int)(signed char) scp->serverLock);
3996         
3997         return 0;
3998     }
3999
4000     osi_Log1(afsd_logp, "cm_UnlockByKey done with %d locks", n_unlocks);
4001
4002     osi_assertx(scp->sharedLocks >= 0, "scp->sharedLocks < 0");
4003     osi_assertx(scp->exclusiveLocks >= 0, "scp->exclusiveLocks < 0");
4004     osi_assertx(scp->clientLocks >= 0, "scp->clientLocks < 0");
4005
4006     if (!SERVERLOCKS_ENABLED(scp)) {
4007         osi_Log0(afsd_logp, "  Skipping server lock for scp");
4008         goto done;
4009     }
4010
4011     /* Ideally we would go through the rest of the locks to determine
4012      * if one or more locks that were formerly in WAITUNLOCK can now
4013      * be put to ACTIVE or WAITLOCK and update scp->exclusiveLocks and
4014      * scp->sharedLocks accordingly.  However, the retrying of locks
4015      * in that manner is done cm_RetryLock() manually.
4016      */
4017
4018     if (scp->serverLock == LockWrite &&
4019         scp->exclusiveLocks == 0 &&
4020         scp->sharedLocks > 0) {
4021
4022         /* The serverLock should be downgraded to LockRead */
4023         osi_Log0(afsd_logp, "  DOWNGRADE lock from LockWrite to LockRead");
4024
4025         /* since scp->serverLock looked sane, we are going to assume
4026            that we have a valid server lock. */
4027         scp->lockDataVersion = scp->dataVersion;
4028         osi_Log1(afsd_logp, "  dataVersion on scp = %d", scp->dataVersion);
4029
4030         code = cm_IntReleaseLock(scp, userp, reqp);
4031
4032         if (code) {
4033             /* so we couldn't release it.  Just let the lock be for now */
4034             code = 0;
4035             goto done;
4036         } else {
4037             scp->serverLock = -1;
4038         }
4039
4040         code = cm_IntSetLock(scp, userp, LockRead, reqp);
4041
4042         if (code == 0 && scp->lockDataVersion == scp->dataVersion) {
4043             scp->serverLock = LockRead;
4044         } else if (code == 0 && scp->lockDataVersion != scp->dataVersion) {
4045             /* We lost a race condition.  Although we have a valid
4046                lock on the file, the data has changed and essentially
4047                we have lost the lock we had during the transition. */
4048
4049             osi_Log0(afsd_logp, "Data version mismatch during lock downgrade");
4050             osi_Log2(afsd_logp, "  Data versions before=%d, after=%d",