windows-dot-dir-part-two-20060906
[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_Gen8Dot3Name(cm_dirEntry_t *dep, char *shortName, char **shortNameEndp)
181 {
182     char number[12];
183     int i, nsize = 0;
184     int vnode = ntohl(dep->fid.vnode);
185     char *lastDot;
186     int validExtension = 0;
187     char tc, *temp, *name;
188
189     /* Unparse the file's vnode number to get a "uniquifier" */
190     do {
191         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
192         nsize++;
193         vnode /= cm_8Dot3MapSize;
194     } while (vnode);
195
196     /*
197      * Look for valid extension.  There has to be a dot, and
198      * at least one of the characters following has to be legal.
199      */
200     lastDot = strrchr(dep->name, '.');
201     if (lastDot) {
202         temp = lastDot; temp++;
203         while (tc = *temp++)
204             if (cm_LegalChars[tc])
205                 break;
206         if (tc)
207             validExtension = 1;
208     }       
209
210     /* Copy name characters */
211     name = dep->name;
212     for (i = 0, name = dep->name;
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 {
335     long rights;
336     long code;
337
338     /* Always allow delete; the RPC will tell us if it's OK */
339     if (desiredAccess == DELETE)
340         return 0;
341
342     rights = 0;
343
344     if (desiredAccess & AFS_ACCESS_READ)
345         rights |= PRSFS_READ;
346
347     if ((desiredAccess & AFS_ACCESS_WRITE)
348          || createDisp == 4)
349         rights |= PRSFS_WRITE;
350
351     lock_ObtainMutex(&scp->mx);
352
353     code = cm_SyncOp(scp, NULL, userp, reqp, rights,
354                       CM_SCACHESYNC_GETSTATUS
355                      | CM_SCACHESYNC_NEEDCALLBACK
356                      | CM_SCACHESYNC_LOCK);
357
358     /*
359      * If the open will fail because the volume is readonly, then we will
360      * return an access denied error instead.  This is to help brain-dead
361      * apps run correctly on replicated volumes.
362      * See defect 10007 for more information.
363      */
364     if (code == CM_ERROR_READONLY)
365         code = CM_ERROR_NOACCESS;
366
367     if (code == 0 &&
368              ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
369              scp->fileType == CM_SCACHETYPE_FILE) {
370         cm_key_t key;
371         unsigned int sLockType;
372         LARGE_INTEGER LOffset, LLength;
373
374         /* Check if there's some sort of lock on the file at the
375            moment. */
376
377         key = cm_GenerateKey(CM_SESSION_CMINT,0,0);
378         if (rights & PRSFS_WRITE)
379             sLockType = 0;
380         else
381             sLockType = LOCKING_ANDX_SHARED_LOCK;
382
383         /* single byte lock at offset 0x0100 0000 0000 0000 */
384         LOffset.HighPart = CM_FLSHARE_OFFSET_HIGH;
385         LOffset.LowPart  = CM_FLSHARE_OFFSET_LOW;
386         LLength.HighPart = CM_FLSHARE_LENGTH_HIGH;
387         LLength.LowPart  = CM_FLSHARE_LENGTH_LOW;
388
389         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
390
391         if (code == 0) {
392             cm_Unlock(scp, sLockType, LOffset, LLength, key, userp, reqp);
393         } else {
394             /* In this case, we allow the file open to go through even
395                though we can't enforce mandatory locking on the
396                file. */
397             if (code == CM_ERROR_NOACCESS &&
398                 !(rights & PRSFS_WRITE))
399                 code = 0;
400             else {
401                 switch (code) {
402                 case CM_ERROR_ALLOFFLINE:
403                 case CM_ERROR_ALLDOWN:
404                 case CM_ERROR_ALLBUSY:
405                 case CM_ERROR_TIMEDOUT:
406                 case CM_ERROR_RETRY:
407                 case CM_ERROR_WOULDBLOCK:
408                     break;
409                 default:
410                     code = CM_ERROR_SHARING_VIOLATION;
411                 }
412             }
413         }
414     } else if (code != 0) {
415         goto _done;
416     }
417
418     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
419
420  _done:
421     lock_ReleaseMutex(&scp->mx);
422
423     return code;
424 }
425
426 /*
427  * When CAP_NT_SMBS has been negotiated, deletion (of files or directories) is
428  * done in three steps:
429  * (1) open for deletion (NT_CREATE_AND_X)
430  * (2) set for deletion on close (NT_TRANSACTION2, SET_FILE_INFO)
431  * (3) close (CLOSE)
432  * We must not do the RPC until step 3.  But if we are going to return an error
433  * code (e.g. directory not empty), we must return it by step 2, otherwise most
434  * clients will not notice it.  So we do a preliminary check.  For deleting
435  * files, this is almost free, since we have already done the RPC to get the
436  * parent directory's status bits.  But for deleting directories, we must do an
437  * additional RPC to get the directory's data to check if it is empty.  Sigh.
438  */
439 long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
440         cm_req_t *reqp)
441 {
442     long code;
443     osi_hyper_t thyper;
444     cm_buf_t *bufferp;
445     cm_dirEntry_t *dep;
446     unsigned short *hashTable;
447     unsigned int i, idx;
448     int BeyondPage = 0, HaveDot = 0, HaveDotDot = 0;
449
450     /* First check permissions */
451     lock_ObtainMutex(&dscp->mx);
452     code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_DELETE,
453                       CM_SCACHESYNC_GETSTATUS
454                       | CM_SCACHESYNC_NEEDCALLBACK);
455     lock_ReleaseMutex(&dscp->mx);
456     if (code)
457         return code;
458
459     /* If deleting directory, must be empty */
460
461     if (scp->fileType != CM_SCACHETYPE_DIRECTORY)
462         return code;
463
464     thyper.HighPart = 0; thyper.LowPart = 0;
465     lock_ObtainRead(&scp->bufCreateLock);
466     code = buf_Get(scp, &thyper, &bufferp);
467     lock_ReleaseRead(&scp->bufCreateLock);
468     if (code)
469         return code;
470
471     lock_ObtainMutex(&bufferp->mx);
472     lock_ObtainMutex(&scp->mx);
473     while (1) {
474         code = cm_SyncOp(scp, bufferp, userp, reqp, 0,
475                           CM_SCACHESYNC_NEEDCALLBACK
476                           | CM_SCACHESYNC_READ
477                           | CM_SCACHESYNC_BUFLOCKED);
478         if (code)
479             break;
480
481         if (cm_HaveBuffer(scp, bufferp, 1))
482             break;
483
484         /* otherwise, load the buffer and try again */
485         lock_ReleaseMutex(&bufferp->mx);
486         code = cm_GetBuffer(scp, bufferp, NULL, userp, reqp);
487         lock_ReleaseMutex(&scp->mx);
488         lock_ObtainMutex(&bufferp->mx);
489         lock_ObtainMutex(&scp->mx);
490         if (code)
491             break;
492     }
493
494     /* We try to determine emptiness without looking beyond the first page,
495      * and without assuming "." and ".." are present and are on the first
496      * page (though these assumptions might, after all, be reasonable).
497      */
498     hashTable = (unsigned short *)(bufferp->datap + (32 * 5));
499     for (i=0; i<128; i++) {
500         idx = ntohs(hashTable[i]);
501         while (idx) {
502             if (idx >= 64) {
503                 BeyondPage = 1;
504                 break;
505             }
506             dep = (cm_dirEntry_t *)(bufferp->datap + (32 * idx));
507             if (strcmp(dep->name, ".") == 0)
508                 HaveDot = 1;
509             else if (strcmp(dep->name, "..") == 0)
510                 HaveDotDot = 1;
511             else {
512                 code = CM_ERROR_NOTEMPTY;
513                 goto done;
514             }
515             idx = ntohs(dep->next);
516         }
517     }
518     if (BeyondPage && HaveDot && HaveDotDot)
519         code = CM_ERROR_NOTEMPTY;
520     else
521         code = 0;
522   done:   
523     lock_ReleaseMutex(&bufferp->mx);
524     buf_Release(bufferp);
525     lock_ReleaseMutex(&scp->mx);
526     return code;
527 }       
528
529 /*
530  * Iterate through all entries in a directory.
531  * When the function funcp is called, the buffer is locked but the
532  * directory vnode is not.
533  *
534  * If the retscp parameter is not NULL, the parmp must be a 
535  * cm_lookupSearch_t object.  
536  */
537 long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
538                   osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
539                   cm_scache_t **retscp)
540 {
541     char *tp;
542     long code;
543     cm_dirEntry_t *dep;
544     cm_buf_t *bufferp;
545     long temp;
546     osi_hyper_t dirLength;
547     osi_hyper_t bufferOffset;
548     osi_hyper_t curOffset;
549     osi_hyper_t thyper;
550     long entryInDir;
551     long entryInBuffer;
552     cm_pageHeader_t *pageHeaderp;
553     int slotInPage;
554     long nextEntryCookie;
555     int numDirChunks;   /* # of 32 byte dir chunks in this entry */
556         
557     /* get the directory size */
558     lock_ObtainMutex(&scp->mx);
559     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
560                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
561     if (code) {
562         lock_ReleaseMutex(&scp->mx);
563         return code;
564     }
565         
566     if (scp->fileType != CM_SCACHETYPE_DIRECTORY) {
567         lock_ReleaseMutex(&scp->mx);
568         return CM_ERROR_NOTDIR;
569     }   
570
571     if (retscp)                         /* if this is a lookup call */
572     {
573         cm_lookupSearch_t*      sp = parmp;
574
575 #ifdef AFS_FREELANCE_CLIENT
576         /* Freelance entries never end up in the DNLC because they
577          * do not have an associated cm_server_t
578          */
579     if ( !(cm_freelanceEnabled &&
580             sp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
581             sp->fid.volume==AFS_FAKE_ROOT_VOL_ID ) )
582 #endif /* AFS_FREELANCE_CLIENT */
583     {
584         int casefold = sp->caseFold;
585         sp->caseFold = 0; /* we have a strong preference for exact matches */
586         if ( *retscp = cm_dnlcLookup(scp, sp))  /* dnlc hit */
587         {
588             sp->caseFold = casefold;
589             lock_ReleaseMutex(&scp->mx);
590             return 0;
591         }
592         sp->caseFold = casefold;
593     }
594     }   
595
596     /*
597      * XXX We only get the length once.  It might change when we drop the
598      * lock.
599      */
600     dirLength = scp->length;
601
602     lock_ReleaseMutex(&scp->mx);
603
604     bufferp = NULL;
605     bufferOffset.LowPart = bufferOffset.HighPart = 0;
606     if (startOffsetp)
607         curOffset = *startOffsetp;
608     else {
609         curOffset.HighPart = 0;
610         curOffset.LowPart = 0;
611     }   
612
613     while (1) {
614         /* make sure that curOffset.LowPart doesn't point to the first
615          * 32 bytes in the 2nd through last dir page, and that it
616          * doesn't point at the first 13 32-byte chunks in the first
617          * dir page, since those are dir and page headers, and don't
618          * contain useful information.
619          */
620         temp = curOffset.LowPart & (2048-1);
621         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
622             /* we're in the first page */
623             if (temp < 13*32) temp = 13*32;
624         }
625         else {
626             /* we're in a later dir page */
627             if (temp < 32) temp = 32;
628         }       
629                 
630         /* make sure the low order 5 bits are zero */
631         temp &= ~(32-1);
632                 
633         /* now put temp bits back ito curOffset.LowPart */
634         curOffset.LowPart &= ~(2048-1);
635         curOffset.LowPart |= temp;
636
637         /* check if we've passed the dir's EOF */
638         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength))
639             break;
640                 
641         /* see if we can use the bufferp we have now; compute in which
642          * page the current offset would be, and check whether that's
643          * the offset of the buffer we have.  If not, get the buffer.
644          */
645         thyper.HighPart = curOffset.HighPart;
646         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
647         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
648             /* wrong buffer */
649             if (bufferp) {
650                 lock_ReleaseMutex(&bufferp->mx);
651                 buf_Release(bufferp);
652                 bufferp = NULL;
653             }
654
655             lock_ObtainRead(&scp->bufCreateLock);
656             code = buf_Get(scp, &thyper, &bufferp);
657             lock_ReleaseRead(&scp->bufCreateLock);
658             if (code) {
659                 /* if buf_Get() fails we do not have a buffer object to lock */
660                 bufferp = NULL;
661                 break;
662             }
663
664 #ifdef AFSIFS
665             /* for the IFS version, we bulkstat the dirents because this
666                routine is used in place of smb_ReceiveCoreSearchDir.  our
667                other option is to modify smb_ReceiveCoreSearchDir itself, 
668                but this seems to be the proper use for cm_ApplyDir. */
669             lock_ObtainMutex(&scp->mx);
670             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
671                  && (scp->bulkStatProgress.QuadPart <= thyper.QuadPart))
672             {
673                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
674                 code = cm_TryBulkStat(scp, &thyper, userp, reqp);
675                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
676                 scp->bulkStatProgress = thyper;
677             }
678             lock_ReleaseMutex(&scp->mx);
679 #endif
680
681             lock_ObtainMutex(&bufferp->mx);
682             bufferOffset = thyper;
683
684             /* now get the data in the cache */
685             while (1) {
686                 lock_ObtainMutex(&scp->mx);
687                 code = cm_SyncOp(scp, bufferp, userp, reqp,
688                                   PRSFS_LOOKUP,
689                                   CM_SCACHESYNC_NEEDCALLBACK
690                                   | CM_SCACHESYNC_READ
691                                   | CM_SCACHESYNC_BUFLOCKED);
692                 if (code) {
693                     lock_ReleaseMutex(&scp->mx);
694                     break;
695                 }
696                                 
697                 if (cm_HaveBuffer(scp, bufferp, 1)) {
698                     lock_ReleaseMutex(&scp->mx);
699                     break;
700                 }
701
702                 /* otherwise, load the buffer and try again */
703                 lock_ReleaseMutex(&bufferp->mx);
704                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
705                                     reqp);
706                 lock_ReleaseMutex(&scp->mx);
707                 lock_ObtainMutex(&bufferp->mx);
708                 if (code) 
709                     break;
710             }
711             if (code) {
712                 lock_ReleaseMutex(&bufferp->mx);
713                 buf_Release(bufferp);
714                 bufferp = NULL;
715                 break;
716             }
717         }       /* if (wrong buffer) ... */
718            
719         /* now we have the buffer containing the entry we're interested
720          * in; copy it out if it represents a non-deleted entry.
721          */
722         entryInDir = curOffset.LowPart & (2048-1);
723         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
724
725         /* page header will help tell us which entries are free.  Page
726          * header can change more often than once per buffer, since
727          * AFS 3 dir page size may be less than (but not more than) a
728          * buffer package buffer.
729          */
730         /* only look intra-buffer */
731         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
732         temp &= ~(2048 - 1);    /* turn off intra-page bits */
733         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
734
735         /* now determine which entry we're looking at in the page.  If
736          * it is free (there's a free bitmap at the start of the dir),
737          * we should skip these 32 bytes.
738          */
739         slotInPage = (entryInDir & 0x7e0) >> 5;
740         if (!(pageHeaderp->freeBitmap[slotInPage>>3]
741                & (1 << (slotInPage & 0x7)))) {
742             /* this entry is free */
743             numDirChunks = 1;   /* only skip this guy */
744             goto nextEntry;
745         }
746
747         tp = bufferp->datap + entryInBuffer;
748         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
749
750         /* while we're here, compute the next entry's location, too,
751          * since we'll need it when writing out the cookie into the
752          * dir listing stream.
753          */
754         numDirChunks = cm_NameEntries(dep->name, NULL);
755                 
756         /* compute the offset of the cookie representing the next entry */
757         nextEntryCookie = curOffset.LowPart
758             + (CM_DIR_CHUNKSIZE * numDirChunks);
759
760         if (dep->fid.vnode != 0) {
761             /* this is one of the entries to use: it is not deleted */
762             code = (*funcp)(scp, dep, parmp, &curOffset);
763             if (code) 
764                 break;
765         }       /* if we're including this name */
766                 
767       nextEntry:
768         /* and adjust curOffset to be where the new cookie is */
769         thyper.HighPart = 0;
770         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
771         curOffset = LargeIntegerAdd(thyper, curOffset);
772     }           /* while copying data for dir listing */
773
774     /* release the mutex */
775     if (bufferp) {
776         lock_ReleaseMutex(&bufferp->mx);
777         buf_Release(bufferp);
778     }
779     return code;
780 }
781
782 int cm_NoneUpper(char *s)
783 {
784     char c;
785     while (c = *s++)
786         if (c >= 'A' && c <= 'Z')
787             return 0;
788     return 1;
789 }
790
791 int cm_NoneLower(char *s)
792 {
793     char c;
794     while (c = *s++)
795         if (c >= 'a' && c <= 'z')
796             return 0;
797     return 1;
798 }
799
800 long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
801                           osi_hyper_t *offp)
802 {
803     cm_lookupSearch_t *sp;
804     int match;
805     char shortName[13];
806     char *matchName;
807
808     sp = (cm_lookupSearch_t *) rockp;
809
810     matchName = dep->name;
811     if (sp->caseFold)
812         match = cm_stricmp(matchName, sp->searchNamep);
813     else
814         match = strcmp(matchName, sp->searchNamep);
815
816     if (match != 0
817          && sp->hasTilde
818          && !cm_Is8Dot3(dep->name)) {
819         matchName = shortName;
820         cm_Gen8Dot3Name(dep, shortName, NULL);
821         if (sp->caseFold)
822             match = cm_stricmp(matchName, sp->searchNamep);
823         else
824             match = strcmp(matchName, sp->searchNamep);
825     }
826
827     if (match != 0)
828         return 0;
829
830     sp->found = 1;
831     if (!sp->caseFold) 
832         sp->ExactFound = 1;
833
834     if (!sp->caseFold || matchName == shortName) {
835         sp->fid.vnode = ntohl(dep->fid.vnode);
836         sp->fid.unique = ntohl(dep->fid.unique);
837         return CM_ERROR_STOPNOW;
838     }
839
840     /*
841      * If we get here, we are doing a case-insensitive search, and we
842      * have found a match.  Now we determine what kind of match it is:
843      * exact, lower-case, upper-case, or none of the above.  This is done
844      * in order to choose among matches, if there are more than one.
845      */
846
847     /* Exact matches are the best. */
848     match = strcmp(matchName, sp->searchNamep);
849     if (match == 0) {
850         sp->ExactFound = 1;
851         sp->fid.vnode = ntohl(dep->fid.vnode);
852         sp->fid.unique = ntohl(dep->fid.unique);
853         return CM_ERROR_STOPNOW;
854     }
855
856     /* Lower-case matches are next. */
857     if (sp->LCfound)
858         return 0;
859     if (cm_NoneUpper(matchName)) {
860         sp->LCfound = 1;
861         goto inexact;
862     }
863
864     /* Upper-case matches are next. */
865     if (sp->UCfound)
866         return 0;
867     if (cm_NoneLower(matchName)) {
868         sp->UCfound = 1;
869         goto inexact;
870     }
871
872     /* General matches are last. */
873     if (sp->NCfound)
874         return 0;
875     sp->NCfound = 1;
876
877   inexact:
878     sp->fid.vnode = ntohl(dep->fid.vnode);
879     sp->fid.unique = ntohl(dep->fid.unique);
880     return 0;
881 }       
882
883 /* read the contents of a mount point into the appropriate string.
884  * called with locked scp, and returns with locked scp.
885  */
886 long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
887 {
888     long code;
889     cm_buf_t *bufp;
890     osi_hyper_t thyper;
891     int tlen;
892
893     if (scp->mountPointStringp[0]) 
894         return 0;
895         
896     /* otherwise, we have to read it in */
897     lock_ReleaseMutex(&scp->mx);
898
899     lock_ObtainRead(&scp->bufCreateLock);
900     thyper.LowPart = thyper.HighPart = 0;
901     code = buf_Get(scp, &thyper, &bufp);
902     lock_ReleaseRead(&scp->bufCreateLock);
903
904     lock_ObtainMutex(&scp->mx);
905     if (code) {
906         return code;
907     }
908     while (1) {
909         code = cm_SyncOp(scp, bufp, userp, reqp, 0,
910                           CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
911         if (code) {
912             goto done;
913         }
914
915         if (cm_HaveBuffer(scp, bufp, 0)) 
916             break;
917
918         /* otherwise load buffer */
919         code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
920         if (code) {
921             goto done;
922         }
923     }
924     /* locked, has callback, has valid data in buffer */
925     if ((tlen = scp->length.LowPart) > 1000) 
926         return CM_ERROR_TOOBIG;
927     if (tlen <= 0) {
928         code = CM_ERROR_INVAL;
929         goto done;
930     }
931
932     /* someone else did the work while we were out */
933     if (scp->mountPointStringp[0]) {
934         code = 0;
935         goto done;
936     }
937
938     /* otherwise, copy out the link */
939     memcpy(scp->mountPointStringp, bufp->datap, tlen);
940
941     /* now make it null-terminated.  Note that the original contents of a
942      * link that is a mount point is "#volname." where "." is there just to
943      * be turned into a null.  That is, we can trash the last char of the
944      * link without damaging the vol name.  This is a stupid convention,
945      * but that's the protocol.
946      */
947     scp->mountPointStringp[tlen-1] = 0;
948     code = 0;
949
950   done:
951     if (bufp) 
952         buf_Release(bufp);
953     return code;
954 }
955
956 /* called with a locked scp and chases the mount point, yielding outScpp.
957  * scp remains locked, just for simplicity of describing the interface.
958  */
959 long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
960                          cm_req_t *reqp, cm_scache_t **outScpp)
961 {
962     char *cellNamep;
963     char *volNamep;
964     int tlen;
965     long code;
966     char *cp;
967     char *mpNamep;
968     cm_volume_t *volp;
969     cm_cell_t *cellp;
970     char mtType;
971     cm_fid_t tfid;
972     size_t vnLength;
973     int type;
974
975     if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
976         tfid = scp->mountRootFid;
977         lock_ReleaseMutex(&scp->mx);
978         code = cm_GetSCache(&tfid, outScpp, userp, reqp);
979         lock_ObtainMutex(&scp->mx);
980         return code;
981     }
982
983     /* parse the volume name */
984     mpNamep = scp->mountPointStringp;
985     if (!mpNamep[0])
986         return CM_ERROR_NOSUCHPATH;
987     tlen = (int)strlen(scp->mountPointStringp);
988     mtType = *scp->mountPointStringp;
989     cellNamep = malloc(tlen);
990     volNamep = malloc(tlen);
991
992     cp = strrchr(mpNamep, ':');
993     if (cp) {
994         /* cellular mount point */
995         memset(cellNamep, 0, tlen);
996         strncpy(cellNamep, mpNamep+1, cp - mpNamep - 1);
997         strcpy(volNamep, cp+1);
998         /* now look up the cell */
999         cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
1000     }
1001     else {
1002         /* normal mt pt */
1003         strcpy(volNamep, mpNamep+1);
1004
1005         cellp = cm_FindCellByID(scp->fid.cell);
1006     }
1007
1008     if (!cellp) {
1009         code = CM_ERROR_NOSUCHCELL;
1010         goto done;
1011     }
1012
1013     vnLength = strlen(volNamep);
1014     if (vnLength >= 8 && strcmp(volNamep + vnLength - 7, ".backup") == 0)
1015         type = BACKVOL;
1016     else if (vnLength >= 10
1017               && strcmp(volNamep + vnLength - 9, ".readonly") == 0)
1018         type = ROVOL;
1019     else
1020         type = RWVOL;
1021
1022     /* check for backups within backups */
1023     if (type == BACKVOL
1024          && (scp->flags & (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
1025          == CM_SCACHEFLAG_RO) {
1026         code = CM_ERROR_NOSUCHVOLUME;
1027         goto done;
1028     }
1029
1030     /* now we need to get the volume */
1031     lock_ReleaseMutex(&scp->mx);
1032     code = cm_GetVolumeByName(cellp, volNamep, userp, reqp, 0, &volp);
1033     lock_ObtainMutex(&scp->mx);
1034         
1035     if (code == 0) {
1036         /* save the parent of the volume root for this is the 
1037          * place where the volume is mounted and we must remember 
1038          * this in the volume structure rather than just in the 
1039          * scache entry lest the scache entry gets recycled 
1040          * (defect 11489)
1041          */
1042         lock_ObtainMutex(&volp->mx);
1043         volp->dotdotFid = dscp->fid;
1044         lock_ReleaseMutex(&volp->mx);
1045
1046         scp->mountRootFid.cell = cellp->cellID;
1047         /* if the mt pt is in a read-only volume (not just a
1048          * backup), and if there is a read-only volume for the
1049          * target, and if this is a type '#' mount point, use
1050          * the read-only, otherwise use the one specified.
1051          */
1052         if (mtType == '#' && (scp->flags & CM_SCACHEFLAG_PURERO)
1053              && volp->roID != 0 && type == RWVOL)
1054             type = ROVOL;
1055         if (type == ROVOL)
1056             scp->mountRootFid.volume = volp->roID;
1057         else if (type == BACKVOL)
1058             scp->mountRootFid.volume = volp->bkID;
1059         else
1060             scp->mountRootFid.volume = volp->rwID;
1061
1062         /* the rest of the fid is a magic number */
1063         scp->mountRootFid.vnode = 1;
1064         scp->mountRootFid.unique = 1;
1065         scp->mountRootGen = cm_data.mountRootGen;
1066
1067         tfid = scp->mountRootFid;
1068         lock_ReleaseMutex(&scp->mx);
1069         code = cm_GetSCache(&tfid, outScpp, userp, reqp);
1070         lock_ObtainMutex(&scp->mx);
1071     }
1072
1073   done:
1074     free(cellNamep);
1075     free(volNamep);
1076     return code;
1077 }       
1078
1079 long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
1080                        cm_req_t *reqp, cm_scache_t **outpScpp)
1081 {
1082     long code;
1083     int dnlcHit = 1;    /* did we hit in the dnlc? yes, we did */
1084     cm_scache_t *tscp = NULL;
1085     cm_scache_t *mountedScp;
1086     cm_lookupSearch_t rock;
1087     int getroot;
1088
1089     if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
1090          && strcmp(namep, "..") == 0) {
1091         if (dscp->dotdotFid.volume == 0)
1092             return CM_ERROR_NOSUCHVOLUME;
1093         rock.fid = dscp->dotdotFid;
1094         goto haveFid;
1095     } else if (strcmp(namep, ".") == 0) {
1096         rock.fid = dscp->fid;
1097         goto haveFid;
1098     }
1099
1100     memset(&rock, 0, sizeof(rock));
1101     rock.fid.cell = dscp->fid.cell;
1102     rock.fid.volume = dscp->fid.volume;
1103     rock.searchNamep = namep;
1104     rock.caseFold = (flags & CM_FLAG_CASEFOLD);
1105     rock.hasTilde = ((strchr(namep, '~') != NULL) ? 1 : 0);
1106
1107     /* If NOMOUNTCHASE, bypass DNLC by passing NULL scp pointer */
1108     code = cm_ApplyDir(dscp, cm_LookupSearchProc, &rock, NULL, userp, reqp,
1109                         (flags & CM_FLAG_NOMOUNTCHASE) ? NULL : &tscp);
1110
1111     /* code == 0 means we fell off the end of the dir, while stopnow means
1112      * that we stopped early, probably because we found the entry we're
1113      * looking for.  Any other non-zero code is an error.
1114      */
1115     if (code && code != CM_ERROR_STOPNOW) {
1116         /* if the cm_scache_t we are searching in is not a directory 
1117          * we must return path not found because the error 
1118          * is to describe the final component not an intermediary
1119          */
1120         if (code == CM_ERROR_NOTDIR) {
1121             if (flags & CM_FLAG_CHECKPATH)
1122                 return CM_ERROR_NOSUCHPATH;
1123             else
1124                 return CM_ERROR_NOSUCHFILE;
1125         }
1126         return code;
1127     }
1128
1129     getroot = (dscp==cm_data.rootSCachep) ;
1130     if (!rock.found) {
1131         if (!cm_freelanceEnabled || !getroot) {
1132             if (flags & CM_FLAG_CHECKPATH)
1133                 return CM_ERROR_NOSUCHPATH;
1134             else
1135                 return CM_ERROR_NOSUCHFILE;
1136         }
1137         else {  /* nonexistent dir on freelance root, so add it */
1138             char fullname[200] = ".";
1139             int  found = 0;
1140
1141             osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s", 
1142                       osi_LogSaveString(afsd_logp,namep));
1143             if (namep[0] == '.') {
1144                 if (cm_GetCell_Gen(&namep[1], &fullname[1], CM_FLAG_CREATE)) {
1145                     found = 1;
1146                     if ( stricmp(&namep[1], &fullname[1]) )
1147                         code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
1148                     else
1149                         code = cm_FreelanceAddMount(namep, &fullname[1], "root.cell.", 1, &rock.fid);
1150                 }
1151             } else {
1152                 if (cm_GetCell_Gen(namep, fullname, CM_FLAG_CREATE)) {
1153                     found = 1;
1154                     if ( stricmp(namep, fullname) )
1155                         code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
1156                     else
1157                         code = cm_FreelanceAddMount(namep, fullname, "root.cell.", 0, &rock.fid);
1158                 }
1159             }
1160             if (!found || code < 0) {   /* add mount point failed, so give up */
1161                 if (flags & CM_FLAG_CHECKPATH)
1162                     return CM_ERROR_NOSUCHPATH;
1163                 else
1164                     return CM_ERROR_NOSUCHFILE;
1165             }
1166             tscp = NULL;   /* to force call of cm_GetSCache */
1167         }
1168     }
1169
1170   haveFid:       
1171     if ( !tscp )    /* we did not find it in the dnlc */
1172     {
1173         dnlcHit = 0;    
1174         code = cm_GetSCache(&rock.fid, &tscp, userp, reqp);
1175         if (code) 
1176             return code;
1177     }       
1178     /* tscp is now held */
1179
1180     lock_ObtainMutex(&tscp->mx);
1181     code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
1182                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1183     if (code) { 
1184         lock_ReleaseMutex(&tscp->mx);
1185         cm_ReleaseSCache(tscp);
1186         return code;
1187     }
1188     /* tscp is now locked */
1189
1190     if (!(flags & CM_FLAG_NOMOUNTCHASE)
1191          && tscp->fileType == CM_SCACHETYPE_MOUNTPOINT) {
1192         /* mount points are funny: they have a volume name to mount
1193          * the root of.
1194          */
1195         code = cm_ReadMountPoint(tscp, userp, reqp);
1196         if (code == 0)
1197             code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
1198                                         &mountedScp);
1199         lock_ReleaseMutex(&tscp->mx);
1200         cm_ReleaseSCache(tscp);
1201         if (code) {
1202             return code;
1203         }
1204         tscp = mountedScp;
1205     }
1206     else {
1207         lock_ReleaseMutex(&tscp->mx);
1208     }
1209
1210     /* copy back pointer */
1211     *outpScpp = tscp;
1212
1213     /* insert scache in dnlc */
1214     if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
1215         /* lock the directory entry to prevent racing callback revokes */
1216         lock_ObtainMutex(&dscp->mx);
1217         if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 )
1218             cm_dnlcEnter(dscp, namep, tscp);
1219         lock_ReleaseMutex(&dscp->mx);
1220     }
1221
1222     /* and return */
1223     return 0;
1224 }
1225
1226 int cm_ExpandSysName(char *inp, char *outp, long outSize, unsigned int index)
1227 {
1228     char *tp;
1229     int prefixCount;
1230
1231     tp = strrchr(inp, '@');
1232     if (tp == NULL) 
1233         return 0;               /* no @sys */
1234
1235     if (strcmp(tp, "@sys") != 0) 
1236         return 0;       /* no @sys */
1237
1238     /* caller just wants to know if this is a valid @sys type of name */
1239     if (outp == NULL) 
1240         return 1;
1241
1242     if (index >= MAXNUMSYSNAMES)
1243         return -1;
1244
1245     /* otherwise generate the properly expanded @sys name */
1246     prefixCount = (int)(tp - inp);
1247
1248     strncpy(outp, inp, prefixCount);    /* copy out "a." from "a.@sys" */
1249     outp[prefixCount] = 0;              /* null terminate the "a." */
1250     strcat(outp, cm_sysNameList[index]);/* append i386_nt40 */
1251     return 1;
1252 }   
1253
1254 long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
1255                cm_req_t *reqp, cm_scache_t **outpScpp)
1256 {
1257     long code;
1258     char tname[256];
1259     int sysNameIndex = 0;
1260     cm_scache_t *scp = NULL;
1261
1262     if ( stricmp(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
1263         if (flags & CM_FLAG_CHECKPATH)
1264             return CM_ERROR_NOSUCHPATH;
1265         else
1266             return CM_ERROR_NOSUCHFILE;
1267     }
1268
1269     for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
1270         code = cm_ExpandSysName(namep, tname, sizeof(tname), sysNameIndex);
1271         if (code > 0) {
1272             code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
1273             if (code == 0) {
1274                 *outpScpp = scp;
1275                 return 0;
1276             }
1277             if (scp) {
1278                 cm_ReleaseSCache(scp);
1279                 scp = NULL;
1280             }
1281         } else {
1282             return cm_LookupInternal(dscp, namep, flags, userp, reqp, outpScpp);
1283         }
1284     }
1285
1286     /* None of the possible sysName expansions could be found */
1287     if (flags & CM_FLAG_CHECKPATH)
1288         return CM_ERROR_NOSUCHPATH;
1289     else
1290         return CM_ERROR_NOSUCHFILE;
1291 }
1292
1293 long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
1294 {
1295     long code;
1296     cm_conn_t *connp;
1297     AFSFid afsFid;
1298     int sflags;
1299     AFSFetchStatus newDirStatus;
1300     AFSVolSync volSync;
1301     struct rx_connection * callp;
1302
1303 #ifdef AFS_FREELANCE_CLIENT
1304     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1305         /* deleting a mount point from the root dir. */
1306         code = cm_FreelanceRemoveMount(namep);
1307         return code;
1308     }
1309 #endif  
1310
1311     /* make sure we don't screw up the dir status during the merge */
1312     lock_ObtainMutex(&dscp->mx);
1313     sflags = CM_SCACHESYNC_STOREDATA;
1314     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags);
1315     lock_ReleaseMutex(&dscp->mx);
1316     if (code) 
1317         return code;
1318
1319     /* make the RPC */
1320     afsFid.Volume = dscp->fid.volume;
1321     afsFid.Vnode = dscp->fid.vnode;
1322     afsFid.Unique = dscp->fid.unique;
1323
1324     osi_Log1(afsd_logp, "CALL RemoveFile scp 0x%p", dscp);
1325     do {
1326         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
1327         if (code) 
1328             continue;
1329
1330         callp = cm_GetRxConn(connp);
1331         code = RXAFS_RemoveFile(callp, &afsFid, namep,
1332                                  &newDirStatus, &volSync);
1333         rx_PutConnection(callp);
1334
1335     } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
1336     code = cm_MapRPCError(code, reqp);
1337
1338     if (code)
1339         osi_Log1(afsd_logp, "CALL RemoveFile FAILURE, code 0x%x", code);
1340     else
1341         osi_Log0(afsd_logp, "CALL RemoveFile SUCCESS");
1342
1343     lock_ObtainMutex(&dscp->mx);
1344     cm_dnlcRemove(dscp, namep);
1345     cm_SyncOpDone(dscp, NULL, sflags);
1346     if (code == 0) 
1347         cm_MergeStatus(dscp, &newDirStatus, &volSync, userp, 0);
1348         else if (code == CM_ERROR_NOSUCHFILE) {
1349                 /* windows would not have allowed the request to delete the file 
1350                  * if it did not believe the file existed.  therefore, we must 
1351                  * have an inconsistent view of the world.
1352                  */
1353                 dscp->cbServerp = NULL;
1354         }
1355     lock_ReleaseMutex(&dscp->mx);
1356
1357     return code;
1358 }
1359
1360 /* called with a locked vnode, and fills in the link info.
1361  * returns this the vnode still locked.
1362  */
1363 long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
1364 {
1365     long code;
1366     cm_buf_t *bufp;
1367     long temp;
1368     osi_hyper_t thyper;
1369
1370     lock_AssertMutex(&linkScp->mx);
1371     if (!linkScp->mountPointStringp[0]) {
1372         /* read the link data */
1373         lock_ReleaseMutex(&linkScp->mx);
1374         thyper.LowPart = thyper.HighPart = 0;
1375         code = buf_Get(linkScp, &thyper, &bufp);
1376         lock_ObtainMutex(&linkScp->mx);
1377         if (code) 
1378             return code;
1379         while (1) {
1380             code = cm_SyncOp(linkScp, bufp, userp, reqp, 0,
1381                               CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
1382             if (code) {
1383                 buf_Release(bufp);
1384                 return code;
1385             }
1386             if (cm_HaveBuffer(linkScp, bufp, 0)) 
1387                 break;
1388
1389             code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
1390             if (code) {
1391                 buf_Release(bufp);
1392                 return code;
1393             }
1394         } /* while loop to get the data */
1395                 
1396         /* now if we still have no link read in,
1397          * copy the data from the buffer */
1398         if ((temp = linkScp->length.LowPart) >= MOUNTPOINTLEN) {
1399             buf_Release(bufp);
1400             return CM_ERROR_TOOBIG;
1401         }
1402
1403         /* otherwise, it fits; make sure it is still null (could have
1404          * lost race with someone else referencing this link above),
1405          * and if so, copy in the data.
1406          */
1407         if (!linkScp->mountPointStringp[0]) {
1408             strncpy(linkScp->mountPointStringp, bufp->datap, temp);
1409             linkScp->mountPointStringp[temp] = 0;       /* null terminate */
1410         }
1411         buf_Release(bufp);
1412     }   /* don't have sym link contents cached */
1413
1414     return 0;
1415 }       
1416
1417 /* called with a held vnode and a path suffix, with the held vnode being a
1418  * symbolic link.  Our goal is to generate a new path to interpret, and return
1419  * this new path in newSpaceBufferp.  If the new vnode is relative to a dir
1420  * other than the directory containing the symbolic link, then the new root is
1421  * returned in *newRootScpp, otherwise a null is returned there.
1422  */
1423 long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
1424                       cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
1425                       cm_user_t *userp, cm_req_t *reqp)
1426 {
1427     long code = 0;
1428     long len;
1429     char *linkp;
1430     cm_space_t *tsp;
1431
1432     lock_ObtainMutex(&linkScp->mx);
1433     code = cm_HandleLink(linkScp, userp, reqp);
1434     if (code) 
1435         goto done;
1436
1437     /* if we may overflow the buffer, bail out; buffer is signficantly
1438      * bigger than max path length, so we don't really have to worry about
1439      * being a little conservative here.
1440      */
1441     if (strlen(linkScp->mountPointStringp) + strlen(pathSuffixp) + 2
1442          >= CM_UTILS_SPACESIZE)
1443         return CM_ERROR_TOOBIG;
1444
1445     tsp = cm_GetSpace();
1446     linkp = linkScp->mountPointStringp;
1447     if (strncmp(linkp, cm_mountRoot, cm_mountRootLen) == 0) {
1448         if (strlen(linkp) > cm_mountRootLen)
1449             strcpy(tsp->data, linkp+cm_mountRootLen+1);
1450         else
1451             tsp->data[0] = 0;
1452         *newRootScpp = cm_data.rootSCachep;
1453         cm_HoldSCache(cm_data.rootSCachep);
1454     } else if (linkp[0] == '\\' && linkp[1] == '\\') {
1455         if (!strnicmp(&linkp[2], cm_NetbiosName, (len = (long)strlen(cm_NetbiosName)))) 
1456         {
1457             char * p = &linkp[len + 3];
1458             if (strnicmp(p, "all", 3) == 0)
1459                 p += 4;
1460
1461             strcpy(tsp->data, p);
1462             for (p = tsp->data; *p; p++) {
1463                 if (*p == '\\')
1464                     *p = '/';
1465             }
1466             *newRootScpp = cm_data.rootSCachep;
1467             cm_HoldSCache(cm_data.rootSCachep);
1468         } else {
1469             linkScp->fileType = CM_SCACHETYPE_DFSLINK;
1470             strcpy(tsp->data, linkp);
1471             *newRootScpp = NULL;
1472             code = CM_ERROR_PATH_NOT_COVERED;
1473         }
1474     } else if ( !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
1475         linkScp->fileType = CM_SCACHETYPE_DFSLINK;
1476         strcpy(tsp->data, linkp);
1477         *newRootScpp = NULL;
1478         code = CM_ERROR_PATH_NOT_COVERED;
1479     } else if (*linkp == '\\' || *linkp == '/') {
1480 #if 0   
1481         /* formerly, this was considered to be from the AFS root,
1482          * but this seems to create problems.  instead, we will just
1483          * reject the link */
1484         strcpy(tsp->data, linkp+1);
1485         *newRootScpp = cm_data.rootSCachep;
1486         cm_HoldSCache(cm_data.rootSCachep);
1487 #else
1488         /* we still copy the link data into the response so that 
1489          * the user can see what the link points to
1490          */
1491         linkScp->fileType = CM_SCACHETYPE_INVALID;
1492         strcpy(tsp->data, linkp);
1493         *newRootScpp = NULL;
1494         code = CM_ERROR_NOSUCHPATH;
1495 #endif  
1496     } else {
1497         /* a relative link */
1498         strcpy(tsp->data, linkp);
1499         *newRootScpp = NULL;
1500     }
1501     if (pathSuffixp[0] != 0) {  /* if suffix string is non-null */
1502         strcat(tsp->data, "\\");
1503         strcat(tsp->data, pathSuffixp);
1504     }
1505     *newSpaceBufferp = tsp;
1506
1507   done:
1508     lock_ReleaseMutex(&linkScp->mx);
1509     return code;
1510 }
1511
1512 long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
1513                cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp)
1514 {
1515     long code;
1516     char *tp;                   /* ptr moving through input buffer */
1517     char tc;                    /* temp char */
1518     int haveComponent;          /* has new component started? */
1519     char component[256];        /* this is the new component */
1520     char *cp;                   /* component name being assembled */
1521     cm_scache_t *tscp;          /* current location in the hierarchy */
1522     cm_scache_t *nscp;          /* next dude down */
1523     cm_scache_t *dirScp;        /* last dir we searched */
1524     cm_scache_t *linkScp;       /* new root for the symlink we just
1525     * looked up */
1526     cm_space_t *psp;            /* space for current path, if we've hit
1527     * any symlinks */
1528     cm_space_t *tempsp;         /* temp vbl */
1529     char *restp;                /* rest of the pathname to interpret */
1530     int symlinkCount;           /* count of # of symlinks traversed */
1531     int extraFlag;              /* avoid chasing mt pts for dir cmd */
1532     int phase = 1;              /* 1 = tidPathp, 2 = pathp */
1533
1534     tp = tidPathp;
1535     if (tp == NULL) {
1536         tp = pathp;
1537         phase = 2;
1538     }
1539     if (tp == NULL) {
1540         tp = "";
1541     }
1542     haveComponent = 0;
1543     psp = NULL;
1544     tscp = rootSCachep;
1545     cm_HoldSCache(tscp);
1546     symlinkCount = 0;
1547     dirScp = NULL;
1548
1549     while (1) {
1550         tc = *tp++;
1551
1552         /* map Unix slashes into DOS ones so we can interpret Unix
1553          * symlinks properly
1554          */
1555         if (tc == '/') 
1556             tc = '\\';
1557
1558         if (!haveComponent) {
1559             if (tc == '\\') {
1560                 continue;
1561             } else if (tc == 0) {
1562                 if (phase == 1) {
1563                     phase = 2;
1564                     tp = pathp;
1565                     continue;
1566                 }
1567                 code = 0;
1568                 break;
1569             } else {
1570                 haveComponent = 1;
1571                 cp = component;
1572                 *cp++ = tc;
1573             }
1574         } else {
1575             /* we have a component here */
1576             if (tc == 0 || tc == '\\') {
1577                 /* end of the component; we're at the last
1578                  * component if tc == 0.  However, if the last
1579                  * is a symlink, we have more to do.
1580                  */
1581                 *cp++ = 0;      /* add null termination */
1582                 if (!strcmp(".",component)) {
1583                     code = 0;
1584                     if (dirScp) {
1585                         cm_ReleaseSCache(dirScp);
1586                         dirScp = NULL;
1587                     }
1588                     break;
1589                 }
1590                 extraFlag = 0;
1591                 if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
1592                     extraFlag = CM_FLAG_NOMOUNTCHASE;
1593                 code = cm_Lookup(tscp, component,
1594                                   flags | extraFlag,
1595                                   userp, reqp, &nscp);
1596                 if (code) {
1597                     cm_ReleaseSCache(tscp);
1598                     if (dirScp)
1599                         cm_ReleaseSCache(dirScp);
1600                     if (psp) 
1601                         cm_FreeSpace(psp);
1602                     if (code == CM_ERROR_NOSUCHFILE && tscp->fileType == CM_SCACHETYPE_SYMLINK)
1603                         return CM_ERROR_NOSUCHPATH;
1604                     else
1605                         return code;
1606                 }       
1607                 haveComponent = 0;      /* component done */
1608                 if (dirScp)
1609                     cm_ReleaseSCache(dirScp);
1610                 dirScp = tscp;          /* for some symlinks */
1611                 tscp = nscp;            /* already held */
1612                 nscp = NULL;
1613                 if (tc == 0 && !(flags & CM_FLAG_FOLLOW) && phase == 2) {
1614                     code = 0;
1615                     if (dirScp) {
1616                         cm_ReleaseSCache(dirScp);
1617                         dirScp = NULL;
1618                     }
1619                     break;
1620                 }
1621
1622                 /* now, if tscp is a symlink, we should follow
1623                  * it and assemble the path again.
1624                  */
1625                 lock_ObtainMutex(&tscp->mx);
1626                 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
1627                                   CM_SCACHESYNC_GETSTATUS
1628                                   | CM_SCACHESYNC_NEEDCALLBACK);
1629                 if (code) {
1630                     lock_ReleaseMutex(&tscp->mx);
1631                     cm_ReleaseSCache(tscp);
1632                     tscp = NULL;
1633                     if (dirScp) {
1634                         cm_ReleaseSCache(dirScp);
1635                         dirScp = NULL;
1636                     }
1637                     break;
1638                 }
1639                 if (tscp->fileType == CM_SCACHETYPE_SYMLINK) {
1640                     /* this is a symlink; assemble a new buffer */
1641                     lock_ReleaseMutex(&tscp->mx);
1642                     if (symlinkCount++ >= MAX_SYMLINK_COUNT) {
1643                         cm_ReleaseSCache(tscp);
1644                         tscp = NULL;
1645                         if (dirScp) {
1646                             cm_ReleaseSCache(dirScp);
1647                             dirScp = NULL;
1648                         }
1649                         if (psp) 
1650                             cm_FreeSpace(psp);
1651                         return CM_ERROR_TOO_MANY_SYMLINKS;
1652                     }
1653                     if (tc == 0) 
1654                         restp = "";
1655                     else 
1656                         restp = tp;
1657                     code = cm_AssembleLink(tscp, restp, &linkScp, &tempsp, userp, reqp);
1658                     if (code) {
1659                         /* something went wrong */
1660                         cm_ReleaseSCache(tscp);
1661                         tscp = NULL;
1662                         if (dirScp) {
1663                             cm_ReleaseSCache(dirScp);
1664                             dirScp = NULL;
1665                         }
1666                         break;
1667                     }
1668
1669                     /* otherwise, tempsp has the new path,
1670                      * and linkScp is the new root from
1671                      * which to interpret that path.
1672                      * Continue with the namei processing,
1673                      * also doing the bookkeeping for the
1674                      * space allocation and tracking the
1675                      * vnode reference counts.
1676                      */
1677                     if (psp) 
1678                         cm_FreeSpace(psp);
1679                     psp = tempsp;
1680                     tp = psp->data;
1681                     cm_ReleaseSCache(tscp);
1682                     tscp = linkScp;
1683                     linkScp = NULL;
1684                     /* already held
1685                      * by AssembleLink
1686                      * now, if linkScp is null, that's
1687                      * AssembleLink's way of telling us that
1688                      * the sym link is relative to the dir
1689                      * containing the link.  We have a ref
1690                      * to it in dirScp, and we hold it now
1691                      * and reuse it as the new spot in the
1692                      * dir hierarchy.
1693                      */
1694                     if (tscp == NULL) {
1695                         tscp = dirScp;
1696                         dirScp = NULL;
1697                     }
1698                 } else {
1699                     /* not a symlink, we may be done */
1700                     lock_ReleaseMutex(&tscp->mx);
1701                     if (tc == 0) {
1702                         if (phase == 1) {
1703                             phase = 2;
1704                             tp = pathp;
1705                             continue;
1706                         }
1707                         if (dirScp) {
1708                             cm_ReleaseSCache(dirScp);
1709                             dirScp = NULL;
1710                         }
1711                         code = 0;
1712                         break;
1713                     }
1714                 }
1715                 if (dirScp) {
1716                     cm_ReleaseSCache(dirScp);
1717                     dirScp = NULL;
1718                 }
1719             } /* end of a component */
1720             else 
1721                 *cp++ = tc;
1722         } /* we have a component */
1723     } /* big while loop over all components */
1724
1725     /* already held */
1726     if (dirScp)
1727         cm_ReleaseSCache(dirScp);
1728     if (psp) 
1729         cm_FreeSpace(psp);
1730     if (code == 0) 
1731         *outScpp = tscp;
1732     else if (tscp)
1733         cm_ReleaseSCache(tscp);
1734     return code;
1735 }
1736
1737 /* called with a dir, and a vnode within the dir that happens to be a symlink.
1738  * We chase the link, and return a held pointer to the target, if it exists,
1739  * in *outScpp.  If we succeed, we return 0, otherwise we return an error code
1740  * and do not hold or return a target vnode.
1741  *
1742  * This is very similar to calling cm_NameI with the last component of a name,
1743  * which happens to be a symlink, except that we've already passed by the name.
1744  *
1745  * This function is typically called by the directory listing functions, which
1746  * encounter symlinks but need to return the proper file length so programs
1747  * like "more" work properly when they make use of the attributes retrieved from
1748  * the dir listing.
1749  *
1750  * The input vnode should not be locked when this function is called.
1751  */
1752 long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
1753                          cm_scache_t **outScpp, cm_user_t *userp, cm_req_t *reqp)
1754 {
1755     long code;
1756     cm_space_t *spacep;
1757     cm_scache_t *newRootScp;
1758
1759     osi_Log1(afsd_logp, "Evaluating symlink scp 0x%p", linkScp);
1760
1761     code = cm_AssembleLink(linkScp, "", &newRootScp, &spacep, userp, reqp);
1762     if (code) 
1763         return code;
1764
1765     /* now, if newRootScp is NULL, we're really being told that the symlink
1766      * is relative to the current directory (dscp).
1767      */
1768     if (newRootScp == NULL) {
1769         newRootScp = dscp;
1770         cm_HoldSCache(dscp);
1771     }
1772
1773     code = cm_NameI(newRootScp, spacep->data,
1774                      CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
1775                      userp, NULL, reqp, outScpp);
1776
1777     if (code == CM_ERROR_NOSUCHFILE)
1778         code = CM_ERROR_NOSUCHPATH;
1779
1780     /* this stuff is allocated no matter what happened on the namei call,
1781      * so free it */
1782     cm_FreeSpace(spacep);
1783     cm_ReleaseSCache(newRootScp);
1784
1785     return code;
1786 }
1787
1788 /* make this big enough so that one buffer of dir pages won't overflow.  We'll
1789  * check anyway, but we want to minimize the chance that we have to leave stuff
1790  * unstat'd.
1791  */
1792 #define CM_BULKMAX              (3 * AFSCBMAX)
1793
1794 /* rock for bulk stat calls */
1795 typedef struct cm_bulkStat {
1796     osi_hyper_t bufOffset;      /* only do it for things in this buffer page */
1797
1798     /* info for the actual call */
1799     int counter;                        /* next free slot */
1800     AFSFid fids[CM_BULKMAX];
1801     AFSFetchStatus stats[CM_BULKMAX];
1802     AFSCallBack callbacks[CM_BULKMAX];
1803 } cm_bulkStat_t;
1804
1805 /* for a given entry, make sure that it isn't in the stat cache, and then
1806  * add it to the list of file IDs to be obtained.
1807  *
1808  * Don't bother adding it if we already have a vnode.  Note that the dir
1809  * is locked, so we have to be careful checking the vnode we're thinking of
1810  * processing, to avoid deadlocks.
1811  */
1812 long cm_TryBulkProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1813                      osi_hyper_t *offp)
1814 {
1815     osi_hyper_t thyper;
1816     cm_bulkStat_t *bsp;
1817     int i;
1818     cm_scache_t *tscp;
1819     cm_fid_t tfid;
1820
1821     bsp = rockp;
1822
1823     /* Don't overflow bsp. */
1824     if (bsp->counter >= CM_BULKMAX)
1825         return CM_ERROR_STOPNOW;
1826
1827     thyper.LowPart = cm_data.buf_blockSize;
1828     thyper.HighPart = 0;
1829     thyper = LargeIntegerAdd(thyper, bsp->bufOffset);
1830
1831     /* thyper is now the first byte past the end of the record we're
1832      * interested in, and bsp->bufOffset is the first byte of the record
1833      * we're interested in.
1834      * Skip data in the others.
1835      * Skip '.' and '..'
1836      */
1837     if (LargeIntegerLessThan(*offp, bsp->bufOffset))
1838         return 0;
1839     if (LargeIntegerGreaterThanOrEqualTo(*offp, thyper))
1840         return CM_ERROR_STOPNOW;
1841     if (strcmp(dep->name, ".") == 0 || strcmp(dep->name, "..") == 0)
1842         return 0;
1843
1844     tfid.cell = scp->fid.cell;
1845     tfid.volume = scp->fid.volume;
1846     tfid.vnode = ntohl(dep->fid.vnode);
1847     tfid.unique = ntohl(dep->fid.unique);
1848     tscp = cm_FindSCache(&tfid);
1849     if (tscp) {
1850         if (lock_TryMutex(&tscp->mx)) {
1851             /* we have an entry that we can look at */
1852             if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
1853                 /* we have a callback on it.  Don't bother
1854                  * fetching this stat entry, since we're happy
1855                  * with the info we have.
1856                  */
1857                 lock_ReleaseMutex(&tscp->mx);
1858                 cm_ReleaseSCache(tscp);
1859                 return 0;
1860             }
1861             lock_ReleaseMutex(&tscp->mx);
1862         }       /* got lock */
1863         cm_ReleaseSCache(tscp);
1864     }   /* found entry */
1865
1866 #ifdef AFS_FREELANCE_CLIENT
1867     // yj: if this is a mountpoint under root.afs then we don't want it
1868     // to be bulkstat-ed, instead, we call getSCache directly and under
1869     // getSCache, it is handled specially.
1870     if  ( cm_freelanceEnabled &&
1871           tfid.cell==AFS_FAKE_ROOT_CELL_ID && 
1872           tfid.volume==AFS_FAKE_ROOT_VOL_ID &&
1873           !(tfid.vnode==0x1 && tfid.unique==0x1) )
1874     {       
1875         osi_Log0(afsd_logp, "cm_TryBulkProc Freelance calls cm_SCache on root.afs mountpoint");
1876         return cm_GetSCache(&tfid, &tscp, NULL, NULL);
1877     }
1878 #endif /* AFS_FREELANCE_CLIENT */
1879
1880     i = bsp->counter++;
1881     bsp->fids[i].Volume = scp->fid.volume;
1882     bsp->fids[i].Vnode = tfid.vnode;
1883     bsp->fids[i].Unique = tfid.unique;
1884     return 0;
1885 }       
1886
1887 /* called with a locked scp and a pointer to a buffer.  Make bulk stat
1888  * calls on all undeleted files in the page of the directory specified.
1889  */
1890 afs_int32
1891 cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
1892                cm_req_t *reqp)
1893 {
1894     long code;
1895     cm_bulkStat_t bb;   /* this is *BIG*, probably 16K or so;
1896                          * watch for stack problems */
1897     AFSCBFids fidStruct;
1898     AFSBulkStats statStruct;
1899     cm_conn_t *connp;
1900     AFSCBs callbackStruct;
1901     long filex;
1902     AFSVolSync volSync;
1903     cm_callbackRequest_t cbReq;
1904     long filesThisCall;
1905     long i;
1906     long j;
1907     cm_scache_t *scp;
1908     cm_fid_t tfid;
1909     struct rx_connection * callp;
1910     int inlinebulk = 0;         /* Did we use InlineBulkStatus RPC or not? */
1911
1912     osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
1913
1914     /* should be on a buffer boundary */
1915     osi_assert((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0);
1916
1917     memset(&bb, 0, sizeof(bb));
1918     bb.bufOffset = *offsetp;
1919
1920     lock_ReleaseMutex(&dscp->mx);
1921     /* first, assemble the file IDs we need to stat */
1922     code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) &bb, offsetp, userp, reqp, NULL);
1923
1924     /* if we failed, bail out early */
1925     if (code && code != CM_ERROR_STOPNOW) {
1926         lock_ObtainMutex(&dscp->mx);
1927         return code;
1928     }
1929
1930     /* otherwise, we may have one or more bulk stat's worth of stuff in bb;
1931      * make the calls to create the entries.  Handle AFSCBMAX files at a
1932      * time.
1933      */
1934     filex = 0;
1935     while (filex < bb.counter) {
1936         filesThisCall = bb.counter - filex;
1937         if (filesThisCall > AFSCBMAX) 
1938             filesThisCall = AFSCBMAX;
1939
1940         fidStruct.AFSCBFids_len = filesThisCall;
1941         fidStruct.AFSCBFids_val = &bb.fids[filex];
1942         statStruct.AFSBulkStats_len = filesThisCall;
1943         statStruct.AFSBulkStats_val = &bb.stats[filex];
1944         callbackStruct.AFSCBs_len = filesThisCall;
1945         callbackStruct.AFSCBs_val = &bb.callbacks[filex];
1946         cm_StartCallbackGrantingCall(NULL, &cbReq);
1947         osi_Log1(afsd_logp, "CALL BulkStatus, %d entries", filesThisCall);
1948         do {
1949             code = cm_Conn(&dscp->fid, userp, reqp, &connp);
1950             if (code) 
1951                 continue;
1952
1953             callp = cm_GetRxConn(connp);
1954             if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
1955                 code = RXAFS_InlineBulkStatus(callp, &fidStruct,
1956                                      &statStruct, &callbackStruct, &volSync);
1957                 if (code == RXGEN_OPCODE) {
1958                     cm_SetServerNoInlineBulk(connp->serverp, 0);
1959                 } else {
1960                     inlinebulk = 1;
1961                 }
1962             }
1963             if (!inlinebulk) {
1964                 code = RXAFS_BulkStatus(callp, &fidStruct,
1965                                         &statStruct, &callbackStruct, &volSync);
1966             }
1967             rx_PutConnection(callp);
1968
1969         } while (cm_Analyze(connp, userp, reqp, &dscp->fid,
1970                              &volSync, NULL, &cbReq, code));
1971         code = cm_MapRPCError(code, reqp);
1972         if (code)
1973             osi_Log2(afsd_logp, "CALL %sBulkStatus FAILURE code 0x%x", 
1974                       inlinebulk ? "Inline" : "", code);
1975         else
1976             osi_Log1(afsd_logp, "CALL %sBulkStatus SUCCESS", inlinebulk ? "Inline" : "");
1977
1978         /* may as well quit on an error, since we're not going to do
1979          * much better on the next immediate call, either.
1980          */
1981         if (code) {
1982             cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
1983             break;
1984         }
1985
1986         /* otherwise, we should do the merges */
1987         for (i = 0; i<filesThisCall; i++) {
1988             j = filex + i;
1989             tfid.cell = dscp->fid.cell;
1990             tfid.volume = bb.fids[j].Volume;
1991             tfid.vnode = bb.fids[j].Vnode;
1992             tfid.unique = bb.fids[j].Unique;
1993             code = cm_GetSCache(&tfid, &scp, userp, reqp);
1994             if (code != 0) 
1995                 continue;
1996
1997             /* otherwise, if this entry has no callback info, 
1998              * merge in this.
1999              */
2000             lock_ObtainMutex(&scp->mx);
2001             /* now, we have to be extra paranoid on merging in this
2002              * information, since we didn't use cm_SyncOp before
2003              * starting the fetch to make sure that no bad races
2004              * were occurring.  Specifically, we need to make sure
2005              * we don't obliterate any newer information in the
2006              * vnode than have here.
2007              *
2008              * Right now, be pretty conservative: if there's a
2009              * callback or a pending call, skip it.
2010              */
2011             if ((scp->cbServerp == NULL || (scp->flags & CM_SCACHEFLAG_EACCESS))
2012                  && !(scp->flags &
2013                        (CM_SCACHEFLAG_FETCHING
2014                          | CM_SCACHEFLAG_STORING
2015                          | CM_SCACHEFLAG_SIZESTORING))) {
2016                 cm_EndCallbackGrantingCall(scp, &cbReq,
2017                                             &bb.callbacks[j],
2018                                             CM_CALLBACK_MAINTAINCOUNT);
2019                 cm_MergeStatus(scp, &bb.stats[j], &volSync, userp, 0);
2020             }       
2021             lock_ReleaseMutex(&scp->mx);
2022             cm_ReleaseSCache(scp);
2023         } /* all files in the response */
2024         /* now tell it to drop the count,
2025          * after doing the vnode processing above */
2026         cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
2027
2028         filex += filesThisCall;
2029     }   /* while there are still more files to process */
2030     lock_ObtainMutex(&dscp->mx);
2031
2032 #if 0
2033     /* If we did the InlineBulk RPC pull out the return code */
2034     if (inlinebulk) {
2035         if ((&bb.stats[0])->errorCode) {
2036             cm_Analyze(NULL /*connp was released by the previous cm_Analyze */, 
2037                         userp, reqp, &dscp->fid, &volSync, NULL, NULL, (&bb.stats[0])->errorCode);
2038             code = cm_MapRPCError((&bb.stats[0])->errorCode, reqp);
2039         }
2040     } else
2041 #endif  
2042     { 
2043         code = 0;
2044     }
2045
2046     osi_Log1(afsd_logp, "END cm_TryBulkStat code = 0x%x", code);
2047     return code;
2048 }       
2049
2050 void cm_StatusFromAttr(AFSStoreStatus *statusp, cm_scache_t *scp, cm_attr_t *attrp)
2051 {
2052     long mask;
2053
2054     /* initialize store back mask as inexpensive local variable */
2055     mask = 0;
2056     memset(statusp, 0, sizeof(AFSStoreStatus));
2057
2058     /* copy out queued info from scache first, if scp passed in */
2059     if (scp) {
2060         if (scp->mask & CM_SCACHEMASK_CLIENTMODTIME) {
2061             statusp->ClientModTime = scp->clientModTime;
2062             mask |= AFS_SETMODTIME;
2063             scp->mask &= ~CM_SCACHEMASK_CLIENTMODTIME;
2064         }
2065     }
2066
2067     if (attrp) {
2068         /* now add in our locally generated request */
2069         if (attrp->mask & CM_ATTRMASK_CLIENTMODTIME) {
2070             statusp->ClientModTime = attrp->clientModTime;
2071             mask |= AFS_SETMODTIME;
2072         }
2073         if (attrp->mask & CM_ATTRMASK_UNIXMODEBITS) {
2074             statusp->UnixModeBits = attrp->unixModeBits;
2075             mask |= AFS_SETMODE;
2076         }
2077         if (attrp->mask & CM_ATTRMASK_OWNER) {
2078             statusp->Owner = attrp->owner;
2079             mask |= AFS_SETOWNER;
2080         }
2081         if (attrp->mask & CM_ATTRMASK_GROUP) {
2082             statusp->Group = attrp->group;
2083             mask |= AFS_SETGROUP;
2084         }
2085     }
2086     statusp->Mask = mask;
2087 }       
2088
2089 /* set the file size, and make sure that all relevant buffers have been
2090  * truncated.  Ensure that any partially truncated buffers have been zeroed
2091  * to the end of the buffer.
2092  */
2093 long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
2094                    cm_req_t *reqp)
2095 {
2096     long code;
2097     int shrinking;
2098
2099     /* start by locking out buffer creation */
2100     lock_ObtainWrite(&scp->bufCreateLock);
2101
2102     /* verify that this is a file, not a dir or a symlink */
2103     lock_ObtainMutex(&scp->mx);
2104     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2105                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2106     if (code) 
2107         goto done;
2108         
2109     if (scp->fileType != CM_SCACHETYPE_FILE) {
2110         code = CM_ERROR_ISDIR;
2111         goto done;
2112     }
2113
2114   startover:
2115     if (LargeIntegerLessThan(*sizep, scp->length))
2116         shrinking = 1;
2117     else
2118         shrinking = 0;
2119
2120     lock_ReleaseMutex(&scp->mx);
2121
2122     /* can't hold scp->mx lock here, since we may wait for a storeback to
2123      * finish if the buffer package is cleaning a buffer by storing it to
2124      * the server.
2125      */
2126     if (shrinking)
2127         buf_Truncate(scp, userp, reqp, sizep);
2128
2129     /* now ensure that file length is short enough, and update truncPos */
2130     lock_ObtainMutex(&scp->mx);
2131
2132     /* make sure we have a callback (so we have the right value for the
2133      * length), and wait for it to be safe to do a truncate.
2134      */
2135     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_WRITE,
2136                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
2137                       | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
2138     if (code) 
2139         goto done;
2140
2141     if (LargeIntegerLessThan(*sizep, scp->length)) {
2142         /* a real truncation.  If truncPos is not set yet, or is bigger
2143          * than where we're truncating the file, set truncPos to this
2144          * new value.
2145          */
2146         if (!shrinking)
2147             goto startover;
2148         if (!(scp->mask & CM_SCACHEMASK_TRUNCPOS)
2149              || LargeIntegerLessThan(*sizep, scp->length)) {
2150             /* set trunc pos */
2151             scp->truncPos = *sizep;
2152             scp->mask |= CM_SCACHEMASK_TRUNCPOS;
2153         }
2154         /* in either case, the new file size has been changed */
2155         scp->length = *sizep;
2156         scp->mask |= CM_SCACHEMASK_LENGTH;
2157     }
2158     else if (LargeIntegerGreaterThan(*sizep, scp->length)) {
2159         /* really extending the file */
2160         scp->length = *sizep;
2161         scp->mask |= CM_SCACHEMASK_LENGTH;
2162     }
2163
2164     /* done successfully */
2165     code = 0;
2166
2167   done:
2168     lock_ReleaseMutex(&scp->mx);
2169     lock_ReleaseWrite(&scp->bufCreateLock);
2170
2171     return code;
2172 }
2173
2174 /* set the file size or other attributes (but not both at once) */
2175 long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
2176                 cm_req_t *reqp)
2177 {
2178     long code;
2179     int flags;
2180     AFSFetchStatus afsOutStatus;
2181     AFSVolSync volSync;
2182     cm_conn_t *connp;
2183     AFSFid tfid;
2184     AFSStoreStatus afsInStatus;
2185     struct rx_connection * callp;
2186
2187     /* handle file length setting */
2188     if (attrp->mask & CM_ATTRMASK_LENGTH)
2189         return cm_SetLength(scp, &attrp->length, userp, reqp);
2190
2191     flags = CM_SCACHESYNC_STORESTATUS;
2192
2193     lock_ObtainMutex(&scp->mx);
2194     /* otherwise, we have to make an RPC to get the status */
2195     code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
2196
2197     /* make the attr structure */
2198     cm_StatusFromAttr(&afsInStatus, scp, attrp);
2199
2200     tfid.Volume = scp->fid.volume;
2201     tfid.Vnode = scp->fid.vnode;
2202     tfid.Unique = scp->fid.unique;
2203
2204     lock_ReleaseMutex(&scp->mx);
2205     if (code) 
2206         return code;
2207
2208     /* now make the RPC */
2209     osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
2210     do {
2211         code = cm_Conn(&scp->fid, userp, reqp, &connp);
2212         if (code) 
2213             continue;
2214
2215         callp = cm_GetRxConn(connp);
2216         code = RXAFS_StoreStatus(callp, &tfid,
2217                                   &afsInStatus, &afsOutStatus, &volSync);
2218         rx_PutConnection(callp);
2219
2220     } while (cm_Analyze(connp, userp, reqp,
2221                          &scp->fid, &volSync, NULL, NULL, code));
2222     code = cm_MapRPCError(code, reqp);
2223
2224     if (code)
2225         osi_Log1(afsd_logp, "CALL StoreStatus FAILURE, code 0x%x", code);
2226     else
2227         osi_Log0(afsd_logp, "CALL StoreStatus SUCCESS");
2228
2229     lock_ObtainMutex(&scp->mx);
2230     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
2231     if (code == 0)
2232         cm_MergeStatus(scp, &afsOutStatus, &volSync, userp,
2233                         CM_MERGEFLAG_FORCE);
2234         
2235     /* if we're changing the mode bits, discard the ACL cache, 
2236      * since we changed the mode bits.
2237      */
2238     if (afsInStatus.Mask & AFS_SETMODE) cm_FreeAllACLEnts(scp);
2239     lock_ReleaseMutex(&scp->mx);
2240     return code;
2241 }       
2242
2243 long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
2244                cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp)
2245 {       
2246     cm_conn_t *connp;
2247     long code;
2248     AFSFid dirAFSFid;
2249     cm_callbackRequest_t cbReq;
2250     AFSFid newAFSFid;
2251     cm_fid_t newFid;
2252     cm_scache_t *scp;
2253     int didEnd;
2254     AFSStoreStatus inStatus;
2255     AFSFetchStatus updatedDirStatus;
2256     AFSFetchStatus newFileStatus;
2257     AFSCallBack newFileCallback;
2258     AFSVolSync volSync;
2259     struct rx_connection * callp;
2260
2261     /* can't create names with @sys in them; must expand it manually first.
2262      * return "invalid request" if they try.
2263      */
2264     if (cm_ExpandSysName(namep, NULL, 0, 0)) {
2265         return CM_ERROR_ATSYS;
2266     }
2267
2268     /* before starting the RPC, mark that we're changing the file data, so
2269      * that someone who does a chmod will know to wait until our call
2270      * completes.
2271      */
2272     lock_ObtainMutex(&dscp->mx);
2273     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2274     if (code == 0) {
2275         cm_StartCallbackGrantingCall(NULL, &cbReq);
2276     }
2277     lock_ReleaseMutex(&dscp->mx);
2278     if (code) {
2279         return code;
2280     }
2281     didEnd = 0;
2282
2283     cm_StatusFromAttr(&inStatus, NULL, attrp);
2284
2285     /* try the RPC now */
2286     osi_Log1(afsd_logp, "CALL CreateFile scp 0x%p", dscp);
2287     do {
2288         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2289         if (code) 
2290             continue;
2291
2292         dirAFSFid.Volume = dscp->fid.volume;
2293         dirAFSFid.Vnode = dscp->fid.vnode;
2294         dirAFSFid.Unique = dscp->fid.unique;
2295
2296         callp = cm_GetRxConn(connp);
2297         code = RXAFS_CreateFile(connp->callp, &dirAFSFid, namep,
2298                                  &inStatus, &newAFSFid, &newFileStatus,
2299                                  &updatedDirStatus, &newFileCallback,
2300                                  &volSync);
2301         rx_PutConnection(callp);
2302
2303     } while (cm_Analyze(connp, userp, reqp,
2304                          &dscp->fid, &volSync, NULL, &cbReq, code));
2305     code = cm_MapRPCError(code, reqp);
2306         
2307     if (code)
2308         osi_Log1(afsd_logp, "CALL CreateFile FAILURE, code 0x%x", code);
2309     else
2310         osi_Log0(afsd_logp, "CALL CreateFile SUCCESS");
2311
2312     lock_ObtainMutex(&dscp->mx);
2313     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2314     if (code == 0) {
2315         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2316     }
2317     lock_ReleaseMutex(&dscp->mx);
2318
2319     /* now try to create the file's entry, too, but be careful to 
2320      * make sure that we don't merge in old info.  Since we weren't locking
2321      * out any requests during the file's creation, we may have pretty old
2322      * info.
2323      */
2324     if (code == 0) {
2325         newFid.cell = dscp->fid.cell;
2326         newFid.volume = dscp->fid.volume;
2327         newFid.vnode = newAFSFid.Vnode;
2328         newFid.unique = newAFSFid.Unique;
2329         code = cm_GetSCache(&newFid, &scp, userp, reqp);
2330         if (code == 0) {
2331             lock_ObtainMutex(&scp->mx);
2332             scp->creator = userp;               /* remember who created it */
2333             if (!cm_HaveCallback(scp)) {
2334                 cm_MergeStatus(scp, &newFileStatus, &volSync,
2335                                 userp, 0);
2336                 cm_EndCallbackGrantingCall(scp, &cbReq,
2337                                             &newFileCallback, 0);
2338                 didEnd = 1;     
2339             }       
2340             lock_ReleaseMutex(&scp->mx);
2341             *scpp = scp;
2342         }
2343     }
2344
2345     /* make sure we end things properly */
2346     if (!didEnd)
2347         cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
2348
2349     return code;
2350 }       
2351
2352 long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
2353 {
2354     long code;
2355
2356     lock_ObtainWrite(&scp->bufCreateLock);
2357     code = buf_CleanVnode(scp, userp, reqp);
2358     lock_ReleaseWrite(&scp->bufCreateLock);
2359     if (code == 0) {
2360         lock_ObtainMutex(&scp->mx);
2361
2362         if (scp->mask & (CM_SCACHEMASK_TRUNCPOS
2363                           | CM_SCACHEMASK_CLIENTMODTIME
2364                           | CM_SCACHEMASK_LENGTH))
2365             code = cm_StoreMini(scp, userp, reqp);
2366
2367         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
2368             code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
2369             scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE);
2370         }
2371
2372         lock_ReleaseMutex(&scp->mx);
2373     }
2374     return code;
2375 }
2376
2377 long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
2378                  cm_user_t *userp, cm_req_t *reqp)
2379 {
2380     cm_conn_t *connp;
2381     long code;
2382     AFSFid dirAFSFid;
2383     cm_callbackRequest_t cbReq;
2384     AFSFid newAFSFid;
2385     cm_fid_t newFid;
2386     cm_scache_t *scp;
2387     int didEnd;
2388     AFSStoreStatus inStatus;
2389     AFSFetchStatus updatedDirStatus;
2390     AFSFetchStatus newDirStatus;
2391     AFSCallBack newDirCallback;
2392     AFSVolSync volSync;
2393     struct rx_connection * callp;
2394
2395     /* can't create names with @sys in them; must expand it manually first.
2396      * return "invalid request" if they try.
2397      */
2398     if (cm_ExpandSysName(namep, NULL, 0, 0)) {
2399         return CM_ERROR_ATSYS;
2400     }
2401
2402     /* before starting the RPC, mark that we're changing the directory
2403      * data, so that someone who does a chmod on the dir will wait until
2404      * our call completes.
2405      */
2406     lock_ObtainMutex(&dscp->mx);
2407     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2408     if (code == 0) {
2409         cm_StartCallbackGrantingCall(NULL, &cbReq);
2410     }
2411     lock_ReleaseMutex(&dscp->mx);
2412     if (code) {
2413         return code;
2414     }
2415     didEnd = 0;
2416
2417     cm_StatusFromAttr(&inStatus, NULL, attrp);
2418
2419     /* try the RPC now */
2420     osi_Log1(afsd_logp, "CALL MakeDir scp 0x%p", dscp);
2421     do {
2422         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2423         if (code) 
2424             continue;
2425
2426         dirAFSFid.Volume = dscp->fid.volume;
2427         dirAFSFid.Vnode = dscp->fid.vnode;
2428         dirAFSFid.Unique = dscp->fid.unique;
2429
2430         callp = cm_GetRxConn(connp);
2431         code = RXAFS_MakeDir(connp->callp, &dirAFSFid, namep,
2432                               &inStatus, &newAFSFid, &newDirStatus,
2433                               &updatedDirStatus, &newDirCallback,
2434                               &volSync);
2435         rx_PutConnection(callp);
2436
2437     } while (cm_Analyze(connp, userp, reqp,
2438                          &dscp->fid, &volSync, NULL, &cbReq, code));
2439     code = cm_MapRPCError(code, reqp);
2440         
2441     if (code)
2442         osi_Log1(afsd_logp, "CALL MakeDir FAILURE, code 0x%x", code);
2443     else
2444         osi_Log0(afsd_logp, "CALL MakeDir SUCCESS");
2445
2446     lock_ObtainMutex(&dscp->mx);
2447     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2448     if (code == 0) {
2449         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2450     }
2451     lock_ReleaseMutex(&dscp->mx);
2452
2453     /* now try to create the new dir's entry, too, but be careful to 
2454      * make sure that we don't merge in old info.  Since we weren't locking
2455      * out any requests during the file's creation, we may have pretty old
2456      * info.
2457      */
2458     if (code == 0) {
2459         newFid.cell = dscp->fid.cell;
2460         newFid.volume = dscp->fid.volume;
2461         newFid.vnode = newAFSFid.Vnode;
2462         newFid.unique = newAFSFid.Unique;
2463         code = cm_GetSCache(&newFid, &scp, userp, reqp);
2464         if (code == 0) {
2465             lock_ObtainMutex(&scp->mx);
2466             if (!cm_HaveCallback(scp)) {
2467                 cm_MergeStatus(scp, &newDirStatus, &volSync,
2468                                 userp, 0);
2469                 cm_EndCallbackGrantingCall(scp, &cbReq,
2470                                             &newDirCallback, 0);
2471                 didEnd = 1;             
2472             }
2473             lock_ReleaseMutex(&scp->mx);
2474             cm_ReleaseSCache(scp);
2475         }
2476     }
2477
2478     /* make sure we end things properly */
2479     if (!didEnd)
2480         cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
2481
2482     /* and return error code */
2483     return code;
2484 }       
2485
2486 long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
2487              cm_user_t *userp, cm_req_t *reqp)
2488 {
2489     cm_conn_t *connp;
2490     long code = 0;
2491     AFSFid dirAFSFid;
2492     AFSFid existingAFSFid;
2493     AFSFetchStatus updatedDirStatus;
2494     AFSFetchStatus newLinkStatus;
2495     AFSVolSync volSync;
2496     struct rx_connection * callp;
2497
2498     if (dscp->fid.cell != sscp->fid.cell ||
2499         dscp->fid.volume != sscp->fid.volume) {
2500         return CM_ERROR_CROSSDEVLINK;
2501     }
2502
2503     lock_ObtainMutex(&dscp->mx);
2504     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2505     lock_ReleaseMutex(&dscp->mx);
2506
2507     if (code)
2508         return code;
2509
2510     /* try the RPC now */
2511     osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
2512     do {
2513         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2514         if (code) continue;
2515
2516         dirAFSFid.Volume = dscp->fid.volume;
2517         dirAFSFid.Vnode = dscp->fid.vnode;
2518         dirAFSFid.Unique = dscp->fid.unique;
2519
2520         existingAFSFid.Volume = sscp->fid.volume;
2521         existingAFSFid.Vnode = sscp->fid.vnode;
2522         existingAFSFid.Unique = sscp->fid.unique;
2523
2524         callp = cm_GetRxConn(connp);
2525         code = RXAFS_Link(callp, &dirAFSFid, namep, &existingAFSFid,
2526             &newLinkStatus, &updatedDirStatus, &volSync);
2527         rx_PutConnection(callp);
2528         osi_Log1(smb_logp,"  RXAFS_Link returns 0x%x", code);
2529
2530     } while (cm_Analyze(connp, userp, reqp,
2531         &dscp->fid, &volSync, NULL, NULL, code));
2532
2533     code = cm_MapRPCError(code, reqp);
2534
2535     if (code)
2536         osi_Log1(afsd_logp, "CALL Link FAILURE, code 0x%x", code);
2537     else
2538         osi_Log0(afsd_logp, "CALL Link SUCCESS");
2539
2540     lock_ObtainMutex(&dscp->mx);
2541     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2542     if (code == 0) {
2543         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2544     }
2545     lock_ReleaseMutex(&dscp->mx);
2546
2547     return code;
2548 }
2549
2550 long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
2551                 cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp)
2552 {
2553     cm_conn_t *connp;
2554     long code;
2555     AFSFid dirAFSFid;
2556     AFSFid newAFSFid;
2557     cm_fid_t newFid;
2558     cm_scache_t *scp;
2559     AFSStoreStatus inStatus;
2560     AFSFetchStatus updatedDirStatus;
2561     AFSFetchStatus newLinkStatus;
2562     AFSVolSync volSync;
2563     struct rx_connection * callp;
2564
2565     /* before starting the RPC, mark that we're changing the directory data,
2566      * so that someone who does a chmod on the dir will wait until our
2567      * call completes.
2568      */
2569     lock_ObtainMutex(&dscp->mx);
2570     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
2571     lock_ReleaseMutex(&dscp->mx);
2572     if (code) {
2573         return code;
2574     }
2575
2576     cm_StatusFromAttr(&inStatus, NULL, attrp);
2577
2578     /* try the RPC now */
2579     osi_Log1(afsd_logp, "CALL Symlink scp 0x%p", dscp);
2580     do {
2581         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2582         if (code) 
2583             continue;
2584
2585         dirAFSFid.Volume = dscp->fid.volume;
2586         dirAFSFid.Vnode = dscp->fid.vnode;
2587         dirAFSFid.Unique = dscp->fid.unique;
2588
2589         callp = cm_GetRxConn(connp);
2590         code = RXAFS_Symlink(callp, &dirAFSFid, namep, contentsp,
2591                               &inStatus, &newAFSFid, &newLinkStatus,
2592                               &updatedDirStatus, &volSync);
2593         rx_PutConnection(callp);
2594
2595     } while (cm_Analyze(connp, userp, reqp,
2596                          &dscp->fid, &volSync, NULL, NULL, code));
2597     code = cm_MapRPCError(code, reqp);
2598         
2599     if (code)
2600         osi_Log1(afsd_logp, "CALL Symlink FAILURE, code 0x%x", code);
2601     else
2602         osi_Log0(afsd_logp, "CALL Symlink SUCCESS");
2603
2604     lock_ObtainMutex(&dscp->mx);
2605     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2606     if (code == 0) {
2607         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2608     }
2609     lock_ReleaseMutex(&dscp->mx);
2610
2611     /* now try to create the new dir's entry, too, but be careful to 
2612      * make sure that we don't merge in old info.  Since we weren't locking
2613      * out any requests during the file's creation, we may have pretty old
2614      * info.
2615      */
2616     if (code == 0) {
2617         newFid.cell = dscp->fid.cell;
2618         newFid.volume = dscp->fid.volume;
2619         newFid.vnode = newAFSFid.Vnode;
2620         newFid.unique = newAFSFid.Unique;
2621         code = cm_GetSCache(&newFid, &scp, userp, reqp);
2622         if (code == 0) {
2623             lock_ObtainMutex(&scp->mx);
2624             if (!cm_HaveCallback(scp)) {
2625                 cm_MergeStatus(scp, &newLinkStatus, &volSync,
2626                                 userp, 0);
2627             }       
2628             lock_ReleaseMutex(&scp->mx);
2629             cm_ReleaseSCache(scp);
2630         }
2631     }
2632         
2633     /* and return error code */
2634     return code;
2635 }
2636
2637 long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
2638                    cm_req_t *reqp)
2639 {
2640     cm_conn_t *connp;
2641     long code;
2642     AFSFid dirAFSFid;
2643     int didEnd;
2644     AFSFetchStatus updatedDirStatus;
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     didEnd = 0;
2659
2660     /* try the RPC now */
2661     osi_Log1(afsd_logp, "CALL RemoveDir scp 0x%p", dscp);
2662     do {
2663         code = cm_Conn(&dscp->fid, userp, reqp, &connp);
2664         if (code) 
2665             continue;
2666
2667         dirAFSFid.Volume = dscp->fid.volume;
2668         dirAFSFid.Vnode = dscp->fid.vnode;
2669         dirAFSFid.Unique = dscp->fid.unique;
2670
2671         callp = cm_GetRxConn(connp);
2672         code = RXAFS_RemoveDir(callp, &dirAFSFid, namep,
2673                                 &updatedDirStatus, &volSync);
2674         rx_PutConnection(callp);
2675
2676     } while (cm_Analyze(connp, userp, reqp,
2677                          &dscp->fid, &volSync, NULL, NULL, code));
2678     code = cm_MapRPCErrorRmdir(code, reqp);
2679
2680     if (code)
2681         osi_Log1(afsd_logp, "CALL RemoveDir FAILURE, code 0x%x", code);
2682     else
2683         osi_Log0(afsd_logp, "CALL RemoveDir SUCCESS");
2684
2685     lock_ObtainMutex(&dscp->mx);
2686     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
2687     if (code == 0) {
2688         cm_dnlcRemove(dscp, namep); 
2689         cm_MergeStatus(dscp, &updatedDirStatus, &volSync, userp, 0);
2690     }
2691     lock_ReleaseMutex(&dscp->mx);
2692
2693     /* and return error code */
2694     return code;
2695 }
2696
2697 long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
2698 {
2699     /* grab mutex on contents */
2700     lock_ObtainMutex(&scp->mx);
2701
2702     /* reset the prefetch info */
2703     scp->prefetch.base.LowPart = 0;             /* base */
2704     scp->prefetch.base.HighPart = 0;
2705     scp->prefetch.end.LowPart = 0;              /* and end */
2706     scp->prefetch.end.HighPart = 0;
2707
2708     /* release mutex on contents */
2709     lock_ReleaseMutex(&scp->mx);
2710
2711     /* we're done */
2712     return 0;
2713 }       
2714
2715 long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
2716                 char *newNamep, cm_user_t *userp, cm_req_t *reqp)
2717 {
2718     cm_conn_t *connp;
2719     long code;
2720     AFSFid oldDirAFSFid;
2721     AFSFid newDirAFSFid;
2722     int didEnd;
2723     AFSFetchStatus updatedOldDirStatus;
2724     AFSFetchStatus updatedNewDirStatus;
2725     AFSVolSync volSync;
2726     int oneDir;
2727     struct rx_connection * callp;
2728
2729     /* before starting the RPC, mark that we're changing the directory data,
2730      * so that someone who does a chmod on the dir will wait until our call
2731      * completes.  We do this in vnode order so that we don't deadlock,
2732      * which makes the code a little verbose.
2733      */
2734     if (oldDscp == newDscp) {
2735         /* check for identical names */
2736         if (strcmp(oldNamep, newNamep) == 0)
2737             return CM_ERROR_RENAME_IDENTICAL;
2738
2739         oneDir = 1;
2740         lock_ObtainMutex(&oldDscp->mx);
2741         cm_dnlcRemove(oldDscp, oldNamep);
2742         cm_dnlcRemove(oldDscp, newNamep);
2743         code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
2744                           CM_SCACHESYNC_STOREDATA);
2745         lock_ReleaseMutex(&oldDscp->mx);
2746     }
2747     else {
2748         /* two distinct dir vnodes */
2749         oneDir = 0;
2750         if (oldDscp->fid.cell != newDscp->fid.cell ||
2751              oldDscp->fid.volume != newDscp->fid.volume)
2752             return CM_ERROR_CROSSDEVLINK;
2753
2754         /* shouldn't happen that we have distinct vnodes for two
2755          * different files, but could due to deliberate attack, or
2756          * stale info.  Avoid deadlocks and quit now.
2757          */
2758         if (oldDscp->fid.vnode == newDscp->fid.vnode)
2759             return CM_ERROR_CROSSDEVLINK;
2760
2761         if (oldDscp->fid.vnode < newDscp->fid.vnode) {
2762             lock_ObtainMutex(&oldDscp->mx);
2763             cm_dnlcRemove(oldDscp, oldNamep);
2764             code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
2765                               CM_SCACHESYNC_STOREDATA);
2766             lock_ReleaseMutex(&oldDscp->mx);
2767             if (code == 0) {
2768                 lock_ObtainMutex(&newDscp->mx);
2769                 cm_dnlcRemove(newDscp, newNamep);
2770                 code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
2771                                   CM_SCACHESYNC_STOREDATA);
2772                 lock_ReleaseMutex(&newDscp->mx);
2773                 if (code) {
2774                     /* cleanup first one */
2775                     lock_ObtainMutex(&newDscp->mx);
2776                     cm_SyncOpDone(oldDscp, NULL,
2777                                    CM_SCACHESYNC_STOREDATA);
2778                     lock_ReleaseMutex(&oldDscp->mx);
2779                 }       
2780             }
2781         }
2782         else {
2783             /* lock the new vnode entry first */
2784             lock_ObtainMutex(&newDscp->mx);
2785             cm_dnlcRemove(newDscp, newNamep);
2786             code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
2787                               CM_SCACHESYNC_STOREDATA);
2788             lock_ReleaseMutex(&newDscp->mx);
2789             if (code == 0) {
2790                 lock_ObtainMutex(&oldDscp->mx);
2791                 cm_dnlcRemove(oldDscp, oldNamep);
2792                 code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
2793                                   CM_SCACHESYNC_STOREDATA);
2794                 lock_ReleaseMutex(&oldDscp->mx);
2795                 if (code) {
2796                     /* cleanup first one */
2797                     lock_ObtainMutex(&newDscp->mx);
2798                     cm_SyncOpDone(newDscp, NULL,
2799                                    CM_SCACHESYNC_STOREDATA);
2800                     lock_ReleaseMutex(&newDscp->mx);
2801                 }       
2802             }
2803         }
2804     }   /* two distinct vnodes */
2805
2806     if (code) {
2807         return code;
2808     }
2809     didEnd = 0;
2810
2811     /* try the RPC now */
2812     osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p", 
2813               oldDscp, newDscp);
2814     do {
2815         code = cm_Conn(&oldDscp->fid, userp, reqp, &connp);
2816         if (code) 
2817             continue;
2818
2819         oldDirAFSFid.Volume = oldDscp->fid.volume;
2820         oldDirAFSFid.Vnode = oldDscp->fid.vnode;
2821         oldDirAFSFid.Unique = oldDscp->fid.unique;
2822         newDirAFSFid.Volume = newDscp->fid.volume;
2823         newDirAFSFid.Vnode = newDscp->fid.vnode;
2824         newDirAFSFid.Unique = newDscp->fid.unique;
2825
2826         callp = cm_GetRxConn(connp);
2827         code = RXAFS_Rename(callp, &oldDirAFSFid, oldNamep,
2828                              &newDirAFSFid, newNamep,
2829                              &updatedOldDirStatus, &updatedNewDirStatus,
2830                              &volSync);
2831         rx_PutConnection(callp);
2832
2833     } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
2834                          &volSync, NULL, NULL, code));
2835     code = cm_MapRPCError(code, reqp);
2836         
2837     if (code)
2838         osi_Log1(afsd_logp, "CALL Rename FAILURE, code 0x%x", code);
2839     else
2840         osi_Log0(afsd_logp, "CALL Rename SUCCESS");
2841
2842     /* update the individual stat cache entries for the directories */
2843     lock_ObtainMutex(&oldDscp->mx);
2844     cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
2845     if (code == 0) {
2846         cm_MergeStatus(oldDscp, &updatedOldDirStatus, &volSync,
2847                         userp, 0);
2848     }
2849     lock_ReleaseMutex(&oldDscp->mx);
2850
2851     /* and update it for the new one, too, if necessary */
2852     if (!oneDir) {
2853         lock_ObtainMutex(&newDscp->mx);
2854         cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
2855         if (code == 0) {
2856             cm_MergeStatus(newDscp, &updatedNewDirStatus, &volSync,
2857                             userp, 0);
2858         }
2859         lock_ReleaseMutex(&newDscp->mx);
2860     }
2861
2862     /* and return error code */
2863     return code;
2864 }
2865
2866 /* Byte range locks:
2867
2868    The OpenAFS Windows client has to fake byte range locks given no
2869    server side support for such locks.  This is implemented as keyed
2870    byte range locks on the cache manager.
2871
2872    Keyed byte range locks:
2873
2874    Each cm_scache_t structure keeps track of a list of keyed locks.
2875    The key for a lock identifies an owner of a set of locks (referred
2876    to as a client).  Each key is represented by a value.  The set of
2877    key values used within a specific cm_scache_t structure form a
2878    namespace that has a scope of just that cm_scache_t structure.  The
2879    same key value can be used with another cm_scache_t structure and
2880    correspond to a completely different client.  However it is
2881    advantageous for the SMB or IFS layer to make sure that there is a
2882    1-1 mapping between client and keys over all cm_scache_t objects.
2883
2884    Assume a client C has key Key(C) (although, since the scope of the
2885    key is a cm_scache_t, the key can be Key(C,S), where S is the
2886    cm_scache_t.  But assume a 1-1 relation between keys and clients).
2887    A byte range (O,+L) denotes byte addresses (O) through (O+L-1)
2888    inclusive (a.k.a. [O,O+L-1]).  The function Key(x) is implemented
2889    through cm_generateKey() function for both SMB and IFS.
2890
2891    The list of locks for a cm_scache_t object S is maintained in
2892    S->fileLocks.  The cache manager will set a lock on the AFS file
2893    server in order to assert the locks in S->fileLocks.  If only
2894    shared locks are in place for S, then the cache manager will obtain
2895    a LockRead lock, while if there are any exclusive locks, it will
2896    obtain a LockWrite lock.  If the exclusive locks are all released
2897    while the shared locks remain, then the cache manager will
2898    downgrade the lock from LockWrite to LockRead.  Similarly, if an
2899    exclusive lock is obtained when only shared locks exist, then the
2900    cache manager will try to upgrade the lock from LockRead to
2901    LockWrite.
2902
2903    Each lock L owned by client C maintains a key L->key such that
2904    L->key == Key(C), the effective range defined by L->LOffset and
2905    L->LLength such that the range of bytes affected by the lock is
2906    (L->LOffset, +L->LLength), a type maintained in L->LockType which
2907    is either exclusive or shared.
2908
2909    Lock states:
2910
2911    A lock exists iff it is in S->fileLocks for some cm_scache_t
2912    S. Existing locks are in one of the following states: ACTIVE,
2913    WAITLOCK, WAITUNLOCK, LOST, DELETED.
2914
2915    The following sections describe each lock and the associated
2916    transitions.
2917
2918    1. ACTIVE: A lock L is ACTIVE iff the cache manager has asserted
2919       the lock with the AFS file server.  This type of lock can be
2920       exercised by a client to read or write to the locked region (as
2921       the lock allows).
2922
2923       1.1 ACTIVE->LOST: When the AFS file server fails to extend a
2924         server lock that was required to assert the lock.  Before
2925         marking the lock as lost, the cache manager checks if the file
2926         has changed on the server.  If the file has not changed, then
2927         the cache manager will attempt to obtain a new server lock
2928         that is sufficient to assert the client side locks for the
2929         file.  If any of these fail, the lock is marked as LOST.
2930         Otherwise, it is left as ACTIVE.
2931
2932       1.2 ACTIVE->DELETED: Lock is released.
2933
2934    2. WAITLOCK: A lock is in a WAITLOCK state if the cache manager
2935       grants the lock but the lock is yet to be asserted with the AFS
2936       file server.  Once the file server grants the lock, the state
2937       will transition to an ACTIVE lock.
2938
2939       2.1 WAITLOCK->ACTIVE: The server granted the lock.
2940
2941       2.2 WAITLOCK->DELETED: Lock is abandoned, or timed out during
2942         waiting.
2943
2944       2.3 WAITLOCK->LOST: One or more locks from this client were
2945         marked as LOST.  No further locks will be granted to this
2946         client until all lost locks are removed.
2947
2948    3. WAITUNLOCK: A lock is in a WAITUNLOCK state if the cache manager
2949       receives a request for a lock that conflicts with an existing
2950       ACTIVE or WAITLOCK lock.  The lock will be placed in the queue
2951       and will be granted at such time the conflicting locks are
2952       removed, at which point the state will transition to either
2953       WAITLOCK or ACTIVE.
2954
2955       3.1 WAITUNLOCK->ACTIVE: The conflicting lock was removed.  The
2956         current serverLock is sufficient to assert this lock, or a
2957         sufficient serverLock is obtained.
2958
2959       3.2 WAITUNLOCK->WAITLOCK: The conflicting lock was removed,
2960         however the required serverLock is yet to be asserted with the
2961         server.
2962
2963       3.3 WAITUNLOCK->DELETED: The lock is abandoned, timed out or
2964         released.
2965
2966       3.5 WAITUNLOCK->LOST: One or more locks from this client were
2967         marked as LOST.  No further locks will be granted to this
2968         client until all lost locks are removed.
2969
2970    4. LOST: A lock L is LOST if the server lock that was required to
2971       assert the lock could not be obtained or if it could not be
2972       extended, or if other locks by the same client were LOST.
2973       Essentially, once a lock is LOST, the contract between the cache
2974       manager and that specific client is no longer valid.
2975
2976       The cache manager rechecks the server lock once every minute and
2977       extends it as appropriate.  If this is not done for 5 minutes,
2978       the AFS file server will release the lock (the 5 minute timeout
2979       is based on current file server code and is fairly arbitrary).
2980       Once released, the lock cannot be re-obtained without verifying
2981       that the contents of the file hasn't been modified since the
2982       time the lock was released.  Re-obtaining the lock without
2983       verifying this may lead to data corruption.  If the lock can not
2984       be obtained safely, then all active locks for the cm_scache_t
2985       are marked as LOST.
2986
2987       4.1 LOST->DELETED: The lock is released.
2988
2989    5. DELETED: The lock is no longer relevant.  Eventually, it will
2990       get removed from the cm_scache_t. In the meantime, it will be
2991       treated as if it does not exist.
2992
2993       5.1 DELETED->not exist: The lock is removed from the
2994         cm_scache_t.
2995
2996    The following are classifications of locks based on their state.
2997
2998    6* A lock L is ACCEPTED if it is ACTIVE or WAITLOCK.  These locks
2999       have been accepted by the cache manager, but may or may not have
3000       been granted back to the client.
3001
3002    7* A lock L is QUEUED if it is ACTIVE, WAITLOCK or WAITUNLOCK.
3003
3004    8* A lock L is WAITING if it is WAITLOCK or WAITUNLOCK.
3005
3006    Lock operation:
3007
3008    A client C can READ range (Offset,+Length) of a file represented by
3009    cm_scache_t S iff (1):
3010
3011    1. for all _a_ in (Offset,+Length), all of the following is true:
3012
3013        1.1 For each ACTIVE lock L in S->fileLocks such that _a_ in
3014          (L->LOffset,+L->LLength); L->key == Key(C) OR L->LockType is
3015          shared.
3016
3017        1.2 For each LOST lock L in S->fileLocks such that _a_ in
3018          (L->LOffset,+L->LLength); L->LockType is shared AND L->key !=
3019          Key(C)
3020
3021        (When locks are lost on an cm_scache_t, all locks are lost.  By
3022        4.2 (below), if there is an exclusive LOST lock, then there
3023        can't be any overlapping ACTIVE locks.)
3024
3025    A client C can WRITE range (Offset,+Length) of cm_scache_t S iff (2):
3026
3027    2. for all _a_ in (Offset,+Length), one of the following is true:
3028
3029        2.1 Byte _a_ of S is unowned (as specified in 1.1) AND there
3030          does not exist a LOST lock L such that _a_ in
3031          (L->LOffset,+L->LLength).
3032
3033        2.2 Byte _a_ of S is owned by C under lock L (as specified in
3034          1.2) AND L->LockType is exclusive.
3035
3036    A client C can OBTAIN a lock L on cm_scache_t S iff (both 3 and 4):
3037
3038    3. for all _a_ in (L->LOffset,+L->LLength), ALL of the following is
3039       true:
3040
3041        3.1 If L->LockType is exclusive then there does NOT exist a
3042          ACCEPTED lock M in S->fileLocks such that _a_ in
3043          (M->LOffset,+M->LLength).
3044
3045          (If we count all QUEUED locks then we hit cases such as
3046          cascading waiting locks where the locks later on in the queue
3047          can be granted without compromising file integrity.  On the
3048          other hand if only ACCEPTED locks are considered, then locks
3049          that were received earlier may end up waiting for locks that
3050          were received later to be unlocked. The choice of ACCEPTED
3051          locks was made to mimic the Windows byte range lock
3052          semantics.)
3053
3054        3.2 If L->LockType is shared then for each ACCEPTED lock M in
3055          S->fileLocks, if _a_ in (M->LOffset,+M->LLength) then
3056          M->LockType is shared.
3057
3058    4. For all LOST locks M in S->fileLocks, ALL of the following are true:
3059
3060        4.1 M->key != Key(C)
3061
3062        4.2 If M->LockType is exclusive, then (L->LOffset,+L->LLength)
3063          and (M->LOffset,+M->LLength) do not intersect.
3064
3065          (Note: If a client loses a lock, it loses all locks.
3066          Subsequently, it will not be allowed to obtain any more locks
3067          until all existing LOST locks that belong to the client are
3068          released.  Once all locks are released by a single client,
3069          there exists no further contract between the client and AFS
3070          about the contents of the file, hence the client can then
3071          proceed to obtain new locks and establish a new contract.
3072
3073          This doesn't quite work as you think it should, because most
3074          applications aren't built to deal with losing locks they
3075          thought they once had.  For now, we don't have a good
3076          solution to lost locks.
3077
3078          Also, for consistency reasons, we have to hold off on
3079          granting locks that overlap exclusive LOST locks.)
3080
3081    A client C can only unlock locks L in S->fileLocks which have
3082    L->key == Key(C).
3083
3084    The representation and invariants are as follows:
3085
3086    - Each cm_scache_t structure keeps:
3087
3088        - A queue of byte-range locks (cm_scache_t::fileLocks) which
3089          are of type cm_file_lock_t.
3090
3091        - A record of the highest server-side lock that has been
3092          obtained for this object (cm_scache_t::serverLock), which is
3093          one of (-1), LockRead, LockWrite.
3094
3095        - A count of ACCEPTED exclusive and shared locks that are in the
3096          queue (cm_scache_t::sharedLocks and
3097          cm_scache_t::exclusiveLocks)
3098
3099    - Each cm_file_lock_t structure keeps:
3100
3101        - The type of lock (cm_file_lock_t::LockType)
3102
3103        - The key associated with the lock (cm_file_lock_t::key)
3104
3105        - The offset and length of the lock (cm_file_lock_t::LOffset
3106          and cm_file_lock_t::LLength)
3107
3108        - The state of the lock.
3109
3110        - Time of issuance or last successful extension
3111
3112    Semantic invariants:
3113
3114        I1. The number of ACCEPTED locks in S->fileLocks are
3115            (S->sharedLocks + S->exclusiveLocks)
3116
3117    External invariants:
3118
3119        I3. S->serverLock is the lock that we have asserted with the
3120            AFS file server for this cm_scache_t.
3121
3122        I4. S->serverLock == LockRead iff there is at least one ACTIVE
3123            shared lock, but no ACTIVE exclusive locks.
3124
3125        I5. S->serverLock == LockWrite iff there is at least one ACTIVE
3126            exclusive lock.
3127
3128        I6. If L is a LOST lock, then for each lock M in S->fileLocks,
3129            M->key == L->key IMPLIES M is LOST or DELETED.
3130
3131    --asanka
3132  */
3133
3134 #define IS_LOCK_ACTIVE(lockp)     (((lockp)->flags & (CM_FILELOCK_FLAG_DELETED|CM_FILELOCK_FLAG_WAITLOCK|CM_FILELOCK_FLAG_WAITUNLOCK|CM_FILELOCK_FLAG_LOST)) == 0)
3135
3136 #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)
3137
3138 #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)
3139
3140 #define IS_LOCK_LOST(lockp)       (((lockp)->flags & (CM_FILELOCK_FLAG_DELETED|CM_FILELOCK_FLAG_LOST)) == CM_FILELOCK_FLAG_LOST)
3141
3142 #define IS_LOCK_DELETED(lockp)    (((lockp)->flags & CM_FILELOCK_FLAG_DELETED) == CM_FILELOCK_FLAG_DELETED)
3143
3144 /* unsafe */
3145 #define IS_LOCK_ACCEPTED(lockp)   (IS_LOCK_ACTIVE(lockp) || IS_LOCK_WAITLOCK(lockp))
3146
3147 /* unsafe */
3148 #define IS_LOCK_CLIENTONLY(lockp) ((((lockp)->scp->flags & CM_SCACHEFLAG_RO) == CM_SCACHEFLAG_RO) || (((lockp)->flags & CM_FILELOCK_FLAG_CLIENTONLY) == CM_FILELOCK_FLAG_CLIENTONLY))
3149
3150 /* unsafe */
3151 #define INTERSECT_RANGE(r1,r2) (((r2).offset+(r2).length) > (r1).offset && ((r1).offset +(r1).length) > (r2).offset)
3152
3153 /* unsafe */
3154 #define CONTAINS_RANGE(r1,r2) (((r2).offset+(r2).length) <= ((r1).offset+(r1).length) && (r1).offset <= (r2).offset)
3155
3156 #if defined(VICED_CAPABILITY_USE_BYTE_RANGE_LOCKS) && !defined(LOCK_TESTING)
3157 #define SCP_SUPPORTS_BRLOCKS(scp) ((scp)->cbServerp && ((scp)->cbServerp->capabilities & VICED_CAPABILITY_USE_BYTE_RANGE_LOCKS))
3158 #else
3159 #define SCP_SUPPORTS_BRLOCKS(scp) (1)
3160 #endif
3161
3162 #define SERVERLOCKS_ENABLED(scp) (!((scp)->flags & CM_SCACHEFLAG_RO) && cm_enableServerLocks && SCP_SUPPORTS_BRLOCKS(scp))
3163
3164 static void cm_LockRangeSubtract(cm_range_t * pos, const cm_range_t * neg)
3165 {
3166     afs_int64 int_begin;
3167     afs_int64 int_end;
3168
3169     int_begin = MAX(pos->offset, neg->offset);
3170     int_end = MIN(pos->offset+pos->length, neg->offset+neg->length);
3171
3172     if (int_begin < int_end) {
3173         if (int_begin == pos->offset) {
3174             pos->length = pos->offset + pos->length - int_end;
3175             pos->offset = int_end;
3176         } else if (int_end == pos->offset + pos->length) {
3177             pos->length = int_begin - pos->offset;
3178         }
3179
3180         /* We only subtract ranges if the resulting range is
3181            contiguous.  If we try to support non-contigous ranges, we
3182            aren't actually improving performance. */
3183     }
3184 }
3185
3186 /* Called with scp->mx held.  Returns 0 if all is clear to read the
3187    specified range by the client identified by key.
3188  */
3189 long cm_LockCheckRead(cm_scache_t *scp, 
3190                       LARGE_INTEGER LOffset, 
3191                       LARGE_INTEGER LLength, 
3192                       cm_key_t key)
3193 {
3194 #ifndef ADVISORY_LOCKS
3195
3196     cm_file_lock_t *fileLock;
3197     osi_queue_t *q;
3198     long code = 0;
3199     cm_range_t range;
3200     int substract_ranges = FALSE;
3201
3202     range.offset = LOffset.QuadPart;
3203     range.length = LLength.QuadPart;
3204
3205     /*
3206
3207      1. for all _a_ in (Offset,+Length), all of the following is true:
3208
3209        1.1 For each ACTIVE lock L in S->fileLocks such that _a_ in
3210          (L->LOffset,+L->LLength); L->key == Key(C) OR L->LockType is
3211          shared.
3212
3213        1.2 For each LOST lock L in S->fileLocks such that _a_ in
3214          (L->LOffset,+L->LLength); L->LockType is shared AND L->key !=
3215          Key(C)
3216
3217     */
3218
3219     lock_ObtainRead(&cm_scacheLock);
3220
3221     for (q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
3222         fileLock = 
3223             (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
3224
3225         if (INTERSECT_RANGE(range, fileLock->range)) {
3226             if (IS_LOCK_ACTIVE(fileLock)) {
3227                 if (fileLock->key == key) {
3228
3229                     /* If there is an active lock for this client, it
3230                        is safe to substract ranges.*/
3231                     cm_LockRangeSubtract(&range, &fileLock->range);
3232                     substract_ranges = TRUE;
3233                 } else {
3234                     if (fileLock->lockType != LockRead) {
3235                         code = CM_ERROR_LOCK_CONFLICT;
3236                         break;
3237                     }
3238
3239                     /* even if the entire range is locked for reading,
3240                        we still can't grant the lock at this point
3241                        because the client may have lost locks. That
3242                        is, unless we have already seen an active lock
3243                        belonging to the client, in which case there
3244                        can't be any lost locks for this client. */
3245                     if (substract_ranges)
3246                         cm_LockRangeSubtract(&range, &fileLock->range);
3247                 }
3248             } else if (IS_LOCK_LOST(fileLock) &&
3249                       (fileLock->key == key || fileLock->lockType == LockWrite)) {
3250                 code = CM_ERROR_BADFD;
3251                 break;
3252             }
3253         }
3254     }
3255
3256     lock_ReleaseRead(&cm_scacheLock);
3257
3258     osi_Log4(afsd_logp, "cm_LockCheckRead scp 0x%x offset %d length %d code 0x%x",
3259               scp, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart, code);
3260
3261     return code;
3262
3263 #else
3264
3265     return 0;
3266
3267 #endif
3268 }
3269
3270 /* Called with scp->mx held.  Returns 0 if all is clear to write the
3271    specified range by the client identified by key.
3272  */
3273 long cm_LockCheckWrite(cm_scache_t *scp,
3274                        LARGE_INTEGER LOffset,
3275                        LARGE_INTEGER LLength,
3276                        cm_key_t key)
3277 {
3278 #ifndef ADVISORY_LOCKS
3279
3280     cm_file_lock_t *fileLock;
3281     osi_queue_t *q;
3282     long code = 0;
3283     cm_range_t range;
3284
3285     range.offset = LOffset.QuadPart;
3286     range.length = LLength.QuadPart;
3287
3288     /*
3289    A client C can WRITE range (Offset,+Length) of cm_scache_t S iff (2):
3290
3291    2. for all _a_ in (Offset,+Length), one of the following is true:
3292
3293        2.1 Byte _a_ of S is unowned AND there does not exist a LOST
3294          lock L such that _a_ in (L->LOffset,+L->LLength).
3295
3296        2.2 Byte _a_ of S is owned by C under lock L AND L->LockType is
3297          exclusive.
3298     */
3299
3300     lock_ObtainRead(&cm_scacheLock);
3301
3302     for (q = scp->fileLocksH; q && range.length > 0; q = osi_QNext(q)) {
3303         fileLock = 
3304             (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
3305
3306         if (INTERSECT_RANGE(range, fileLock->range)) {
3307             if (IS_LOCK_ACTIVE(fileLock)) {
3308                 if (fileLock->key == key) {
3309                     if (fileLock->lockType == LockWrite) {
3310
3311                         /* if there is an active lock for this client, it
3312                            is safe to substract ranges */
3313                         cm_LockRangeSubtract(&range, &fileLock->range);
3314                     } else {
3315                         code = CM_ERROR_LOCK_CONFLICT;
3316                         break;
3317                     }
3318                 } else {
3319                     code = CM_ERROR_LOCK_CONFLICT;
3320                     break;
3321                 }
3322             } else if (IS_LOCK_LOST(fileLock)) {
3323                 code = CM_ERROR_BADFD;
3324                 break;
3325             }
3326         }
3327     }
3328
3329     lock_ReleaseRead(&cm_scacheLock);
3330
3331     osi_Log4(afsd_logp, "cm_LockCheckWrite scp 0x%x offset %d length %d code 0x%x",
3332               scp, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart, code);
3333
3334     return code;
3335
3336 #else
3337
3338     return 0;
3339
3340 #endif
3341 }
3342
3343 /* Forward dcl. */
3344 static void cm_LockMarkSCacheLost(cm_scache_t * scp);
3345
3346 /* Called with cm_scacheLock write locked */
3347 static cm_file_lock_t * cm_GetFileLock(void) {
3348     cm_file_lock_t * l;
3349
3350     l = (cm_file_lock_t *) cm_freeFileLocks;
3351     if (l) {
3352         osi_QRemove(&cm_freeFileLocks, &l->q);
3353     } else {
3354         l = malloc(sizeof(cm_file_lock_t));
3355         osi_assert(l);
3356     }
3357
3358     memset(l, 0, sizeof(cm_file_lock_t));
3359
3360     return l;
3361 }
3362
3363 /* Called with cm_scacheLock write locked */
3364 static void cm_PutFileLock(cm_file_lock_t *l) {
3365     osi_QAdd(&cm_freeFileLocks, &l->q);
3366 }
3367
3368 /* called with scp->mx held.  May release it during processing, but
3369    leaves it held on exit. */
3370 long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
3371                    cm_req_t * reqp) {
3372     long code = 0;
3373     AFSFid tfid;
3374     cm_fid_t cfid;
3375     cm_conn_t * connp;
3376     struct rx_connection * callp;
3377     AFSVolSync volSync;
3378
3379     tfid.Volume = scp->fid.volume;
3380     tfid.Vnode = scp->fid.vnode;
3381     tfid.Unique = scp->fid.unique;
3382     cfid = scp->fid;
3383
3384     osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
3385
3386     lock_ReleaseMutex(&scp->mx);
3387
3388     do {
3389         code = cm_Conn(&cfid, userp, reqp, &connp);
3390         if (code) 
3391             break;
3392
3393         callp = cm_GetRxConn(connp);
3394         code = RXAFS_SetLock(callp, &tfid, lockType,
3395                              &volSync);
3396         rx_PutConnection(callp);
3397
3398     } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
3399                         NULL, NULL, code));
3400
3401     code = cm_MapRPCError(code, reqp);
3402     if (code) {
3403         osi_Log1(afsd_logp, "CALL SetLock FAILURE, code 0x%x", code);
3404     } else {
3405         osi_Log0(afsd_logp, "CALL SetLock SUCCESS");
3406     }
3407
3408     lock_ObtainMutex(&scp->mx);
3409
3410     return code;
3411 }
3412
3413 /* called with scp->mx held.  Releases it during processing */
3414 long cm_IntReleaseLock(cm_scache_t * scp, cm_user_t * userp,
3415                        cm_req_t * reqp) {
3416     long code = 0;
3417     AFSFid tfid;
3418     cm_fid_t cfid;
3419     cm_conn_t * connp;
3420     struct rx_connection * callp;
3421     AFSVolSync volSync;
3422
3423     tfid.Volume = scp->fid.volume;
3424     tfid.Vnode = scp->fid.vnode;
3425     tfid.Unique = scp->fid.unique;
3426     cfid = scp->fid;
3427
3428     lock_ReleaseMutex(&scp->mx);
3429
3430     osi_Log1(afsd_logp, "CALL ReleaseLock scp 0x%p", scp);
3431
3432     do {
3433         code = cm_Conn(&cfid, userp, reqp, &connp);
3434         if (code) 
3435             break;
3436
3437         callp = cm_GetRxConn(connp);
3438         code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
3439         rx_PutConnection(callp);
3440
3441     } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
3442                         NULL, NULL, code));
3443     code = cm_MapRPCError(code, reqp);
3444     if (code)
3445         osi_Log1(afsd_logp,
3446                  "CALL ReleaseLock FAILURE, code 0x%x", code);
3447     else
3448         osi_Log0(afsd_logp,
3449                  "CALL ReleaseLock SUCCESS");
3450         
3451     lock_ObtainMutex(&scp->mx);
3452
3453     return code;
3454 }
3455
3456 /* called with scp->mx held.  May release it during processing, but
3457    will exit with lock held.
3458
3459    This will return:
3460
3461    - 0 if the user has permission to get the specified lock for the scp
3462
3463    - CM_ERROR_NOACCESS if not
3464
3465    Any other error from cm_SyncOp will be sent down untranslated.
3466 */
3467 long cm_LockCheckPerms(cm_scache_t * scp,
3468                        int lock_type,
3469                        cm_user_t * userp,
3470                        cm_req_t * reqp)
3471 {
3472     long rights = 0;
3473     long code = 0;
3474
3475     /* lock permissions are slightly tricky because of the 'i' bit.
3476        If the user has PRSFS_LOCK, she can read-lock the file.  If the
3477        user has PRSFS_WRITE, she can write-lock the file.  However, if
3478        the user has PRSFS_INSERT, then she can write-lock new files,
3479        but not old ones.  Since we don't have information about
3480        whether a file is new o