48d4074dccacb28164a435beeaccb89fb5ad85b8
[openafs.git] / src / WINNT / afsd / smb.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 //#define NOSERVICE 1
11
12 #define NOMOREFILESFIX 1
13
14 #include <afs/param.h>
15 #include <afs/stds.h>
16
17 #ifndef DJGPP
18 #include <windows.h>
19 #else
20 #include <sys/timeb.h>
21 #include <tzfile.h>
22 #endif /* !DJGPP */
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <malloc.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <time.h>
29
30 #include <osi.h>
31
32 #include "afsd.h"
33
34 #include "smb.h"
35 #include "lanahelper.h"
36
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
40
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
43
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
47 unsigned long loggedOutTime;
48 int loggedOut = 0;
49 int smbShutdownFlag = 0;
50
51 int smb_LogoffTokenTransfer;
52 unsigned long smb_LogoffTransferTimeout;
53
54 DWORD last_msg_time = 0;
55
56 long ongoingOps = 0;
57
58 unsigned int sessionGen = 0;
59
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
62
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
65
66 osi_log_t *  smb_logp;
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t  smb_ListenerLock;
70  
71 char smb_LANadapter;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
73
74 /* for debugging */
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
77
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
79
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
82
83 int smb_NumServerThreads;
84
85 int numNCBs, numSessions;
86
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
89
90 #define NCBmax MAXIMUM_WAIT_OBJECTS
91 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
92 EVENT_HANDLE **NCBreturns;
93 DWORD NCBsessions[NCBmax];
94 NCB *NCBs[NCBmax];
95 struct smb_packet *bufs[NCBmax];
96
97 #define Sessionmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE SessionEvents[Sessionmax];
99 unsigned short LSNs[Sessionmax];
100 int lanas[Sessionmax];
101 BOOL dead_sessions[Sessionmax];
102 LANA_ENUM lana_list;
103
104 /* for raw I/O */
105 osi_mutex_t smb_RawBufLock;
106 #ifdef DJGPP
107 #define SMB_RAW_BUFS 4
108 dos_ptr smb_RawBufs;
109 int smb_RawBufSel[SMB_RAW_BUFS];
110 #else
111 char *smb_RawBufs;
112 #endif /* DJGPP */
113
114 #define SMB_MASKFLAG_TILDE 1
115 #define SMB_MASKFLAG_CASEFOLD 2
116
117 #define RAWTIMEOUT INFINITE
118
119 /* for raw write */
120 typedef struct raw_write_cont {
121         long code;
122         osi_hyper_t offset;
123         long count;
124 #ifndef DJGPP
125         char *buf;
126 #else
127         dos_ptr buf;
128 #endif /* DJGPP */
129         int writeMode;
130         long alreadyWritten;
131 } raw_write_cont_t;
132
133 /* dir search stuff */
134 long smb_dirSearchCounter = 1;
135 smb_dirSearch_t *smb_firstDirSearchp;
136 smb_dirSearch_t *smb_lastDirSearchp;
137
138 /* hide dot files? */
139 int smb_hideDotFiles;
140
141 /* global state about V3 protocols */
142 int smb_useV3;          /* try to negotiate V3 */
143
144 #ifndef DJGPP
145 static showErrors = 1;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
148 extern HANDLE WaitToTerminate;
149 #endif /* DJGPP */
150
151 /* GMT time info:
152  * Time in Unix format of midnight, 1/1/1970 local time.
153  * When added to dosUTime, gives Unix (AFS) time.
154  */
155 long smb_localZero;
156
157 /* Time difference for converting to kludge-GMT */
158 int smb_NowTZ;
159
160 char *smb_localNamep = NULL;
161
162 smb_vc_t *smb_allVCsp;
163
164 smb_username_t *usernamesp = NULL;
165
166 smb_waitingLock_t *smb_allWaitingLocks;
167
168 /* forward decl */
169 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
170                                                 NCB *ncbp, raw_write_cont_t *rwcp);
171 void smb_NetbiosInit();
172 #ifdef DJGPP
173 #ifndef AFS_WIN95_ENV
174 DWORD smb_ServerExceptionFilter(void);
175 #endif
176
177 extern char cm_HostName[];
178 extern char cm_confDir[];
179 #endif
180
181 #ifdef DJGPP
182 #define LPTSTR char *
183 #define GetComputerName(str, sizep) \
184        strcpy((str), cm_HostName); \
185        *(sizep) = strlen(cm_HostName)
186 #endif /* DJGPP */
187
188 extern char AFSConfigKeyName[];
189
190 /*
191  * Demo expiration
192  *
193  * To build an expiring version, comment out the definition of NOEXPIRE,
194  * and set the definition of EXPIREDATE to the desired value.
195  */
196 #define NOEXPIRE 1
197 #define EXPIREDATE 834000000            /* Wed Jun 5 1996 */
198
199
200 char * myCrt_Dispatch(int i)
201 {
202         switch (i)
203         {
204         default:
205                 return "unknown SMB op";
206         case 0x00:
207                 return "(00)ReceiveCoreMakeDir";
208         case 0x01:
209                 return "(01)ReceiveCoreRemoveDir";
210         case 0x02:
211                 return "(02)ReceiveCoreOpen";
212         case 0x03:
213                 return "(03)ReceiveCoreCreate";
214         case 0x04:
215                 return "(04)ReceiveCoreClose";
216         case 0x05:
217                 return "(05)ReceiveCoreFlush";
218         case 0x06:
219                 return "(06)ReceiveCoreUnlink";
220         case 0x07:
221                 return "(07)ReceiveCoreRename";
222         case 0x08:
223                 return "(08)ReceiveCoreGetFileAttributes";
224         case 0x09:
225                 return "(09)ReceiveCoreSetFileAttributes";
226         case 0x0a:
227                 return "(0a)ReceiveCoreRead";
228         case 0x0b:
229                 return "(0b)ReceiveCoreWrite";
230         case 0x0c:
231                 return "(0c)ReceiveCoreLockRecord";
232         case 0x0d:
233                 return "(0d)ReceiveCoreUnlockRecord";
234         case 0x0e:
235                 return "(0e)SendCoreBadOp";
236         case 0x0f:
237                 return "(0f)ReceiveCoreCreate";
238         case 0x10:
239                 return "(10)ReceiveCoreCheckPath";
240         case 0x11:
241                 return "(11)SendCoreBadOp";
242         case 0x12:
243                 return "(12)ReceiveCoreSeek";
244         case 0x1a:
245                 return "(1a)ReceiveCoreReadRaw";
246         case 0x1d:
247                 return "(1d)ReceiveCoreWriteRawDummy";
248         case 0x22:
249                 return "(22)ReceiveV3SetAttributes";
250         case 0x23:
251                 return "(23)ReceiveV3GetAttributes";
252         case 0x24:
253                 return "(24)ReceiveV3LockingX";
254         case 0x29:
255                 return "(29)SendCoreBadOp";
256         case 0x2b:
257                 return "(2b)ReceiveCoreEcho";
258         case 0x2d:
259                 return "(2d)ReceiveV3OpenX";
260         case 0x2e:
261                 return "(2e)ReceiveV3ReadX";
262         case 0x32:
263                 return "(32)ReceiveV3Tran2A";
264         case 0x33:
265                 return "(33)ReceiveV3Tran2A";
266         case 0x34:
267                 return "(34)ReceiveV3FindClose";
268         case 0x35:
269                 return "(35)ReceiveV3FindNotifyClose";
270         case 0x70:
271                 return "(70)ReceiveCoreTreeConnect";
272         case 0x71:
273                 return "(71)ReceiveCoreTreeDisconnect";
274         case 0x72:
275                 return "(72)ReceiveNegotiate";
276         case 0x73:
277                 return "(73)ReceiveV3SessionSetupX";
278         case 0x74:
279                 return "(74)ReceiveV3UserLogoffX";
280         case 0x75:
281                 return "(75)ReceiveV3TreeConnectX";
282         case 0x80:
283                 return "(80)ReceiveCoreGetDiskAttributes";
284         case 0x81:
285                 return "(81)ReceiveCoreSearchDir";
286         case 0xA0:
287                 return "(A0)ReceiveNTTransact";
288         case 0xA2:
289                 return "(A2)ReceiveNTCreateX";
290         case 0xA4:
291                 return "(A4)ReceiveNTCancel";
292         case 0xc0:
293                 return "(c0)SendCoreBadOp";
294         case 0xc1:
295                 return "(c1)SendCoreBadOp";
296         case 0xc2:
297                 return "(c2)SendCoreBadOp";
298         case 0xc3:
299                 return "(c3)SendCoreBadOp";
300         }
301 }
302
303 char * myCrt_2Dispatch(int i)
304 {
305         switch (i)
306         {
307         default:
308                 return "unknown SMB op-2";
309         case 0:
310                 return "S(00)CreateFile";
311         case 1:
312                 return "S(01)FindFirst";
313         case 2:
314                 return "S(02)FindNext"; /* FindNext */
315         case 3:
316                 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
317         case 4:
318                 return "S(04)??";
319         case 5:
320                 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
321         case 6:
322                 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
323         case 7:
324                 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
325         case 8:
326                 return "S(08)??_ReceiveTran2SetFileInfo";
327         case 9:
328                 return "S(09)??_ReceiveTran2FSCTL";
329         case 10:
330                 return "S(0a)_ReceiveTran2IOCTL";
331         case 11:
332                 return "S(0b)_ReceiveTran2FindNotifyFirst";
333         case 12:
334                 return "S(0c)_ReceiveTran2FindNotifyNext";
335         case 13:
336                 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
337         }
338 }
339
340 /* scache must be locked */
341 unsigned int smb_Attributes(cm_scache_t *scp)
342 {
343         unsigned int attrs;
344
345         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
346                 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
347                 attrs = SMB_ATTR_DIRECTORY;
348         else
349                 attrs = 0;
350
351         /*
352          * We used to mark a file RO if it was in an RO volume, but that
353          * turns out to be impolitic in NT.  See defect 10007.
354          */
355 #ifdef notdef
356         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
357 #endif
358         if ((scp->unixModeBits & 0222) == 0)
359                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
360
361         return attrs;
362 }
363
364 /* Check if the named file/dir is a dotfile/dotdir */
365 /* String pointed to by lastComp can have leading slashes, but otherwise should have
366    no other patch components */
367 unsigned int smb_IsDotFile(char *lastComp) {
368         char *s;
369         if(lastComp) {
370                 /* skip over slashes */
371         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
372         }
373         else
374                 return 0;
375
376     /* nulls, curdir and parent dir doesn't count */
377         if(!*s) return 0;
378         if(*s == '.') {
379                 if(!*(s + 1)) return 0;
380                 if(*(s+1) == '.' && !*(s + 2)) return 0;
381                 return 1;
382         }
383         return 0;
384 }
385
386 static int ExtractBits(WORD bits, short start, short len)
387 {
388         int end;
389         WORD num;
390
391         end = start + len;
392         
393         num = bits << (16 - end);
394         num = num >> ((16 - end) + start);
395
396         return (int)num;
397 }
398
399 #ifndef DJGPP
400 void ShowUnixTime(char *FuncName, long unixTime)
401 {
402         FILETIME ft;
403         WORD wDate, wTime;
404
405         smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
406                 
407         if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
408                 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
409         else {
410                 int day, month, year, sec, min, hour;
411                 char msg[256];
412
413                 day = ExtractBits(wDate, 0, 5);
414                 month = ExtractBits(wDate, 5, 4);
415                 year = ExtractBits(wDate, 9, 7) + 1980;
416
417                 sec = ExtractBits(wTime, 0, 5);
418                 min = ExtractBits(wTime, 5, 6);
419                 hour = ExtractBits(wTime, 11, 5);
420
421                 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
422                 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
423         }
424 }
425 #endif /* DJGPP */
426
427 #ifndef DJGPP
428 /* Determine if we are observing daylight savings time */
429 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
430 {
431         TIME_ZONE_INFORMATION timeZoneInformation;
432         SYSTEMTIME utc, local, localDST;
433
434         /* Get the time zone info. NT uses this to calc if we are in DST. */
435         GetTimeZoneInformation(&timeZoneInformation);
436  
437         /* Return the daylight bias */
438         *pDstBias = timeZoneInformation.DaylightBias;
439
440         /* Return the bias */
441         *pBias = timeZoneInformation.Bias;
442
443         /* Now determine if DST is being observed */
444
445         /* Get the UTC (GMT) time */
446         GetSystemTime(&utc);
447
448         /* Convert UTC time to local time using the time zone info.  If we are
449            observing DST, the calculated local time will include this. 
450         */
451         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
452
453         /* Set the daylight bias to 0.  The daylight bias is the amount of change
454            in time that we use for daylight savings time.  By setting this to 0
455            we cause there to be no change in time during daylight savings time. 
456         */
457         timeZoneInformation.DaylightBias = 0;
458
459         /* Convert the utc time to local time again, but this time without any
460            adjustment for daylight savings time. 
461         */
462         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
463
464         /* If the two times are different, then it means that the localDST that
465            we calculated includes the daylight bias, and therefore we are
466            observing daylight savings time.
467         */
468         *pDST = localDST.wHour != local.wHour;
469 }
470 #else
471 /* Determine if we are observing daylight savings time */
472 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
473 {
474         struct timeb t;
475
476         ftime(&t);
477         *pDST = t.dstflag;
478         *pDstBias = -60;    /* where can this be different? */
479         *pBias = t.timezone;
480 }
481 #endif /* DJGPP */
482  
483
484 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
485 {
486         BOOL dst;       /* Will be TRUE if observing DST */
487         LONG dstBias;   /* Offset from local time if observing DST */
488         LONG bias;      /* Offset from GMT for local time */
489
490         /*
491          * This function will adjust the last write time to compensate
492          * for two bugs in the smb client:
493          *
494          *    1) During Daylight Savings Time, the LastWriteTime is ahead
495          *       in time by the DaylightBias (ignoring the sign - the
496          *       DaylightBias is always stored as a negative number).  If
497          *       the DaylightBias is -60, then the LastWriteTime will be
498          *       ahead by 60 minutes.
499          *
500          *    2) If the local time zone is a positive offset from GMT, then
501          *       the LastWriteTime will be the correct local time plus the
502          *       Bias (ignoring the sign - a positive offset from GMT is
503          *       always stored as a negative Bias).  If the Bias is -120,
504          *       then the LastWriteTime will be ahead by 120 minutes.
505          *
506          *    These bugs can occur at the same time.
507          */
508
509         GetTimeZoneInfo(&dst, &dstBias, &bias);
510
511         /* First adjust for DST */
512         if (dst)
513                 *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
514
515         /* Now adjust for a positive offset from GMT (a negative bias). */
516         if (bias < 0)
517                 *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
518 }               
519
520 /*
521  * Calculate the difference (in seconds) between local time and GMT.
522  * This enables us to convert file times to kludge-GMT.
523  */
524 static void
525 smb_CalculateNowTZ()
526 {
527         time_t t;
528         struct tm gmt_tm, local_tm;
529         int days, hours, minutes, seconds;
530
531         t = time(NULL);
532         gmt_tm = *(gmtime(&t));
533         local_tm = *(localtime(&t));
534
535         days = local_tm.tm_yday - gmt_tm.tm_yday;
536         hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
537 #ifdef COMMENT
538         /* There is a problem with DST immediately after the time change
539          * which may continue to exist until the machine is rebooted
540          */
541         - (local_tm.tm_isdst ? 1 : 0)
542 #endif /* COMMENT */
543         ;
544         minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
545         seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
546
547         smb_NowTZ = seconds;
548 }
549
550 #ifndef DJGPP
551 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
552 {
553         struct tm *ltp;
554         SYSTEMTIME stm;
555         struct tm localJunk;
556         long ersatz_unixTime;
557
558         /*
559          * Must use kludge-GMT instead of real GMT.
560          * kludge-GMT is computed by adding time zone difference to localtime.
561          *
562          * real GMT would be:
563          * ltp = gmtime(&unixTime);
564          */
565         ersatz_unixTime = unixTime - smb_NowTZ;
566         ltp = localtime(&ersatz_unixTime);
567
568         /* if we fail, make up something */
569         if (!ltp) {
570                 ltp = &localJunk;
571                 localJunk.tm_year = 89 - 20;
572                 localJunk.tm_mon = 4;
573                 localJunk.tm_mday = 12;
574                 localJunk.tm_hour = 0;
575                 localJunk.tm_min = 0;
576                 localJunk.tm_sec = 0;
577         }
578
579         stm.wYear = ltp->tm_year + 1900;
580         stm.wMonth = ltp->tm_mon + 1;
581         stm.wDayOfWeek = ltp->tm_wday;
582         stm.wDay = ltp->tm_mday;
583         stm.wHour = ltp->tm_hour;
584         stm.wMinute = ltp->tm_min;
585         stm.wSecond = ltp->tm_sec;
586         stm.wMilliseconds = 0;
587
588         SystemTimeToFileTime(&stm, largeTimep);
589 }
590 #else /* DJGPP */
591 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
592 {
593         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
594         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
595         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
596         LARGE_INTEGER ut;
597         int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
598
599         /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
600         *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
601                                    * 24 * 60);
602         *ft = LargeIntegerMultiplyByLong(*ft, 60);
603         *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
604
605         /* add unix time */
606         ut = ConvertLongToLargeInteger(unixTime);
607         ut = LargeIntegerMultiplyByLong(ut, 10000000);
608         *ft = LargeIntegerAdd(*ft, ut);
609 }
610 #endif /* !DJGPP */
611
612 #ifndef DJGPP
613 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
614 {
615         SYSTEMTIME stm;
616         struct tm lt;
617         long save_timezone;
618
619         FileTimeToSystemTime(largeTimep, &stm);
620
621         lt.tm_year = stm.wYear - 1900;
622         lt.tm_mon = stm.wMonth - 1;
623         lt.tm_wday = stm.wDayOfWeek;
624         lt.tm_mday = stm.wDay;
625         lt.tm_hour = stm.wHour;
626         lt.tm_min = stm.wMinute;
627         lt.tm_sec = stm.wSecond;
628         lt.tm_isdst = -1;
629
630         save_timezone = _timezone;
631         _timezone += smb_NowTZ;
632         *unixTimep = mktime(&lt);
633         _timezone = save_timezone;
634 }
635 #else /* DJGPP */
636 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
637 {
638         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
639         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
640         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
641         LARGE_INTEGER a;
642         int leap_years = 89;
643
644         /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
645         a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
646         a = LargeIntegerMultiplyByLong(a, 60);
647         a = LargeIntegerMultiplyByLong(a, 10000000);
648
649         /* subtract it from ft */
650         a = LargeIntegerSubtract(*ft, a);
651
652         /* divide down to seconds */
653         *unixTimep = LargeIntegerDivideByLong(a, 10000000);
654 }
655 #endif /* !DJGPP */
656
657 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
658 {
659         struct tm *ltp;
660         int dosDate;
661         int dosTime;
662         struct tm localJunk;
663
664         ltp = localtime((time_t*) &unixTime);
665
666         /* if we fail, make up something */
667         if (!ltp) {
668                 ltp = &localJunk;
669                 localJunk.tm_year = 89 - 20;
670                 localJunk.tm_mon = 4;
671                 localJunk.tm_mday = 12;
672                 localJunk.tm_hour = 0;
673                 localJunk.tm_min = 0;
674                 localJunk.tm_sec = 0;
675         }       
676
677         dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
678         dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
679         *dosTimep = (dosDate<<16) | dosTime;
680 }       
681
682 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
683 {
684         unsigned short dosDate;
685         unsigned short dosTime;
686         struct tm localTm;
687         
688         dosDate = searchTime & 0xffff;
689         dosTime = (searchTime >> 16) & 0xffff;
690         
691         localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
692         localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;    /* January is 0 in localTm */
693         localTm.tm_mday = (dosDate) & 0x1f;
694         localTm.tm_hour = (dosTime>>11) & 0x1f;
695         localTm.tm_min = (dosTime >> 5) & 0x3f;
696         localTm.tm_sec = (dosTime & 0x1f) * 2;
697         localTm.tm_isdst = -1;                          /* compute whether DST in effect */
698
699         *unixTimep = mktime(&localTm);
700 }
701
702 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
703 {
704         *dosUTimep = unixTime - smb_localZero;
705 }
706
707 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
708 {
709 #ifndef DJGPP
710         *unixTimep = dosTime + smb_localZero;
711 #else /* DJGPP */
712         /* dosTime seems to be already adjusted for GMT */
713         *unixTimep = dosTime;
714 #endif /* !DJGPP */
715 }
716
717 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
718 {
719         smb_vc_t *vcp;
720
721         lock_ObtainWrite(&smb_rctLock);
722         for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
723                 if (lsn == vcp->lsn && lana == vcp->lana) {
724                         vcp->refCount++;
725                         break;
726                 }
727         }
728         if (!vcp && (flags & SMB_FLAG_CREATE)) {
729                 vcp = malloc(sizeof(*vcp));
730                 memset(vcp, 0, sizeof(*vcp));
731                 vcp->refCount = 1;
732                 vcp->tidCounter = 1;
733                 vcp->fidCounter = 1;
734                 vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
735                 vcp->nextp = smb_allVCsp;
736                 smb_allVCsp = vcp;
737                 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
738                 vcp->lsn = lsn;
739                 vcp->lana = lana;
740         }
741         lock_ReleaseWrite(&smb_rctLock);
742         return vcp;
743 }
744
745 int smb_IsStarMask(char *maskp)
746 {
747         int i;
748         char tc;
749         
750         for(i=0; i<11; i++) {
751                 tc = *maskp++;
752                 if (tc == '?' || tc == '*' || tc == '>') return 1;        
753         }       
754         return 0;
755 }
756
757 void smb_ReleaseVC(smb_vc_t *vcp)
758 {
759         lock_ObtainWrite(&smb_rctLock);
760         osi_assert(vcp->refCount-- > 0);
761         lock_ReleaseWrite(&smb_rctLock);
762 }
763
764 void smb_HoldVC(smb_vc_t *vcp)
765 {
766         lock_ObtainWrite(&smb_rctLock);
767         vcp->refCount++;
768         lock_ReleaseWrite(&smb_rctLock);
769 }
770
771 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
772 {
773         smb_tid_t *tidp;
774
775         lock_ObtainWrite(&smb_rctLock);
776         for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
777                 if (tid == tidp->tid) {
778                         tidp->refCount++;
779                         break;
780                 }       
781         }
782         if (!tidp && (flags & SMB_FLAG_CREATE)) {
783                 tidp = malloc(sizeof(*tidp));
784                 memset(tidp, 0, sizeof(*tidp));
785                 tidp->nextp = vcp->tidsp;
786                 tidp->refCount = 1;
787                 tidp->vcp = vcp;
788         vcp->refCount++;
789                 vcp->tidsp = tidp;
790                 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
791                 tidp->tid = tid;
792         }
793         lock_ReleaseWrite(&smb_rctLock);
794         return tidp;
795 }       
796
797 void smb_ReleaseTID(smb_tid_t *tidp)
798 {
799         smb_tid_t *tp;
800         smb_tid_t **ltpp;
801         cm_user_t *userp;
802     smb_vc_t  *vcp;
803
804         userp = NULL;
805     vcp = NULL;
806         lock_ObtainWrite(&smb_rctLock);
807         osi_assert(tidp->refCount-- > 0);
808         if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
809                 ltpp = &tidp->vcp->tidsp;
810                 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
811                         if (tp == tidp) break;
812                 }
813                 osi_assert(tp != NULL);
814                 *ltpp = tp->nextp;
815                 lock_FinalizeMutex(&tidp->mx);
816                 userp = tidp->userp;    /* remember to drop ref later */
817         vcp = tidp->vcp;
818         }
819         lock_ReleaseWrite(&smb_rctLock);
820         if (userp) {
821                 cm_ReleaseUser(userp);
822         }       
823     if (vcp) {
824         smb_ReleaseVC(vcp);
825     }
826 }       
827
828 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
829 {
830         smb_user_t *uidp = NULL;
831
832         lock_ObtainWrite(&smb_rctLock);
833         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
834                 if (uid == uidp->userID) {
835                         uidp->refCount++;
836                         osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp) ? uidp->unp->name : "");
837                 break;
838                 }
839         }
840         if (!uidp && (flags & SMB_FLAG_CREATE)) {
841                 uidp = malloc(sizeof(*uidp));
842                 memset(uidp, 0, sizeof(*uidp));
843                 uidp->nextp = vcp->usersp;
844                 uidp->refCount = 1;
845                 uidp->vcp = vcp;
846         vcp->refCount++;
847                 vcp->usersp = uidp;
848                 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
849                 uidp->userID = uid;
850                 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
851         }
852         lock_ReleaseWrite(&smb_rctLock);
853         return uidp;
854 }       
855
856 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
857 {
858         smb_username_t *unp= NULL;
859
860         lock_ObtainWrite(&smb_rctLock);
861         for(unp = usernamesp; unp; unp = unp->nextp) {
862                 if (stricmp(unp->name, usern) == 0 &&
863                         stricmp(unp->machine, machine) == 0) {
864                         unp->refCount++;
865                         break;
866                 }
867         }
868         if (!unp && (flags & SMB_FLAG_CREATE)) {
869                 unp = malloc(sizeof(*unp));
870                 memset(unp, 0, sizeof(*unp));
871                 unp->refCount = 1;
872                 unp->nextp = usernamesp;
873                 unp->name = strdup(usern);
874                 unp->machine = strdup(machine);
875                 usernamesp = unp;
876                 lock_InitializeMutex(&unp->mx, "username_t mutex");
877         }
878         lock_ReleaseWrite(&smb_rctLock);
879         return unp;
880 }       
881
882 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
883 {
884         smb_user_t *uidp= NULL;
885
886         lock_ObtainWrite(&smb_rctLock);
887         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
888                 if (!uidp->unp) 
889             continue;
890                 if (stricmp(uidp->unp->name, usern) == 0) {
891             uidp->refCount++;
892                         osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
893             break;
894                 } else
895             continue;
896         }       
897         lock_ReleaseWrite(&smb_rctLock);
898         return uidp;
899 }
900 void smb_ReleaseUID(smb_user_t *uidp)
901 {
902         smb_user_t *up;
903         smb_user_t **lupp;
904         cm_user_t *userp;
905     smb_vc_t  *vcp;
906
907         userp = NULL;
908     vcp = NULL;
909         lock_ObtainWrite(&smb_rctLock);
910         osi_assert(uidp->refCount-- > 0);
911         if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
912                 lupp = &uidp->vcp->usersp;
913                 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
914                         if (up == uidp) break;
915                 }
916                 osi_assert(up != NULL);
917                 *lupp = up->nextp;
918                 lock_FinalizeMutex(&uidp->mx);
919                 if (uidp->unp) {
920                         userp = uidp->unp->userp;       /* remember to drop ref later */
921             uidp->unp->userp = NULL;
922         }
923         vcp = uidp->vcp;
924         uidp->vcp = NULL;
925         }               
926         lock_ReleaseWrite(&smb_rctLock);
927         if (userp) {
928                 cm_ReleaseUserVCRef(userp);
929                 cm_ReleaseUser(userp);
930         }       
931     if (vcp) {
932         smb_ReleaseVC(vcp);
933     }
934 }       
935
936 /* retrieve a held reference to a user structure corresponding to an incoming
937  * request.
938  * corresponding release function is cm_ReleaseUser.
939  */
940 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
941 {
942         smb_user_t *uidp;
943         cm_user_t *up;
944         smb_t *smbp;
945
946         smbp = (smb_t *) inp;
947         uidp = smb_FindUID(vcp, smbp->uid, 0);
948         if ((!uidp) ||  (!uidp->unp))
949                 return NULL;
950         
951         lock_ObtainMutex(&uidp->mx);
952         up = uidp->unp->userp;
953         cm_HoldUser(up);
954         lock_ReleaseMutex(&uidp->mx);
955
956         smb_ReleaseUID(uidp);
957         
958         return up;
959 }
960
961 /*
962  * Return a pointer to a pathname extracted from a TID structure.  The
963  * TID structure is not held; assume it won't go away.
964  */
965 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
966 {
967         smb_tid_t *tidp;
968         char *tpath;
969
970         tidp = smb_FindTID(vcp, tid, 0);
971     if (!tidp) 
972         return NULL;
973         tpath = tidp->pathname;
974         smb_ReleaseTID(tidp);
975         return tpath;
976 }
977
978 /* check to see if we have a chained fid, that is, a fid that comes from an
979  * OpenAndX message that ran earlier in this packet.  In this case, the fid
980  * field in a read, for example, request, isn't set, since the value is
981  * supposed to be inherited from the openAndX call.
982  */
983 int smb_ChainFID(int fid, smb_packet_t *inp)
984 {
985         if (inp->fid == 0 || inp->inCount == 0) 
986                 return fid;
987         else 
988                 return inp->fid;
989 }
990
991 /* are we a priv'd user?  What does this mean on NT? */
992 int smb_SUser(cm_user_t *userp)
993 {
994         return 1;
995 }
996
997 /* find a file ID.  If we pass in 0 we select an used File ID.
998  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
999  * smb_fid_t data structure if desired File ID cannot be found.
1000  */
1001 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1002 {
1003         smb_fid_t *fidp;
1004         int newFid = 0;
1005         
1006     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1007         return NULL;
1008
1009         lock_ObtainWrite(&smb_rctLock);
1010         /* figure out if we need to allocate a new file ID */
1011         if (fid == 0) {
1012                 newFid = 1;
1013                 fid = vcp->fidCounter;
1014         }
1015
1016 retry:
1017         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1018                 if (fid == fidp->fid) {
1019                         if (newFid) {
1020                                 fid++;
1021                 if (fid == 0) 
1022                                         fid = 1;
1023                 goto retry;
1024             }
1025                         fidp->refCount++;
1026             break;
1027                 }
1028     }
1029     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1030         char eventName[MAX_PATH];
1031         EVENT_HANDLE event;
1032         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1033         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1034         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1035             afsi_log("Event Object Already Exists: %s", eventName);
1036             thrd_CloseHandle(event);
1037             fid++;
1038             if (fid == 0)
1039                 fid = 1;
1040             goto retry;
1041         }
1042
1043                 fidp = malloc(sizeof(*fidp));
1044         memset(fidp, 0, sizeof(*fidp));
1045                 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1046         fidp->refCount = 1;
1047         fidp->vcp = vcp;
1048         vcp->refCount++;
1049         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1050         fidp->fid = fid;
1051                 fidp->curr_chunk = fidp->prev_chunk = -2;
1052                 fidp->raw_write_event = event;
1053         if (newFid) {
1054             vcp->fidCounter = fid+1;
1055             if (vcp->fidCounter == 0) 
1056                 vcp->fidCounter = 1;
1057         }
1058     }
1059     lock_ReleaseWrite(&smb_rctLock);
1060     return fidp;
1061 }
1062
1063 void smb_ReleaseFID(smb_fid_t *fidp)
1064 {
1065         cm_scache_t *scp;
1066     smb_vc_t *vcp = NULL;
1067     smb_ioctl_t *ioctlp;
1068
1069     if (!fidp)
1070         return;
1071
1072         scp = NULL;
1073         lock_ObtainWrite(&smb_rctLock);
1074         osi_assert(fidp->refCount-- > 0);
1075     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1076                 vcp = fidp->vcp;
1077                 if (!(fidp->flags & SMB_FID_IOCTL))
1078                         scp = fidp->scp;
1079                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1080                 thrd_CloseHandle(fidp->raw_write_event);
1081
1082                 /* and see if there is ioctl stuff to free */
1083         ioctlp = fidp->ioctlp;
1084         if (ioctlp) {
1085                         if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1086                         if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1087                         if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1088                         free(ioctlp);
1089         }
1090
1091         free(fidp);
1092
1093         /* do not call smb_ReleaseVC() because we already have the lock */
1094         vcp->refCount--;
1095     }
1096         lock_ReleaseWrite(&smb_rctLock);
1097
1098         /* now release the scache structure */
1099         if (scp) 
1100                 cm_ReleaseSCache(scp);
1101 }
1102
1103 /*
1104  * Case-insensitive search for one string in another;
1105  * used to find variable names in submount pathnames.
1106  */
1107 static char *smb_stristr(char *str1, char *str2)
1108 {
1109         char *cursor;
1110
1111         for (cursor = str1; *cursor; cursor++)
1112                 if (stricmp(cursor, str2) == 0)
1113                         return cursor;
1114
1115         return NULL;
1116 }
1117
1118 /*
1119  * Substitute a variable value for its name in a submount pathname.  Variable
1120  * name has been identified by smb_stristr() and is in substr.  Variable name
1121  * length (plus one) is in substr_size.  Variable value is in newstr.
1122  */
1123 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1124         char *newstr)
1125 {
1126         char temp[1024];
1127
1128         strcpy(temp, substr + substr_size - 1);
1129         strcpy(substr, newstr);
1130         strcat(str1, temp);
1131 }
1132
1133 char VNUserName[] = "%USERNAME%";
1134 char VNLCUserName[] = "%LCUSERNAME%";
1135 char VNComputerName[] = "%COMPUTERNAME%";
1136 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1137
1138 /* List available shares */
1139 int smb_ListShares()
1140 {
1141         char sbmtpath[256];
1142         char pathName[256];
1143         char shareBuf[4096];
1144         int num_shares=0;
1145         char *this_share;
1146         int len;
1147         char *p;
1148         int print_afs = 0;
1149         int code;
1150
1151         /*strcpy(shareNameList[num_shares], "all");
1152          strcpy(pathNameList[num_shares++], "/afs");*/
1153         fprintf(stderr, "The following shares are available:\n");
1154         fprintf(stderr, "Share Name (AFS Path)\n");
1155         fprintf(stderr, "---------------------\n");
1156         fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1157
1158 #ifndef DJGPP
1159         code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1160         if (code == 0 || code > sizeof(sbmtpath)) return -1;
1161 #else
1162         strcpy(sbmtpath, cm_confDir);
1163 #endif /* !DJGPP */
1164         strcat(sbmtpath, "/afsdsbmt.ini");
1165         len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1166                                                                    shareBuf, sizeof(shareBuf),
1167                                                                    sbmtpath);
1168         if (len == 0) {
1169                 return num_shares;
1170         }
1171
1172         this_share = shareBuf;
1173         do
1174         {
1175                 print_afs = 0;
1176                 /*strcpy(shareNameList[num_shares], this_share);*/
1177                 len = GetPrivateProfileString("AFS Submounts", this_share,
1178                                                                            NULL,
1179                                                                            pathName, 256,
1180                                                                            sbmtpath);
1181                 if (!len) 
1182                         return num_shares;
1183                 p = pathName;
1184                 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1185             print_afs = 1;
1186                 while (*p) {
1187             if (*p == '\\') *p = '/';    /* change to / */
1188             p++;
1189                 }
1190
1191                 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1192                                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1193                                  pathName);
1194                 num_shares++;
1195                 while (*this_share != 0) this_share++;  /* find next NUL */
1196                 this_share++;   /* skip past the NUL */
1197         } while (*this_share != 0);  /* stop at final NUL */
1198
1199         return num_shares;
1200 }
1201
1202 /* find a shareName in the table of submounts */
1203 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1204         char **pathNamep)
1205 {
1206         DWORD len;
1207         char pathName[1024];
1208         char *var;
1209         smb_user_t *uidp;
1210         char temp[1024];
1211         DWORD sizeTemp;
1212     char sbmtpath[MAX_PATH];
1213     char *p, *q;
1214         HKEY parmKey;
1215         DWORD code;
1216     DWORD allSubmount = 1;
1217
1218         if (strcmp(shareName, "IPC$") == 0) {
1219                 *pathNamep = NULL;
1220                 return 0;
1221         }
1222
1223     /* if allSubmounts == 0, only return the //mountRoot/all share 
1224      * if in fact it has been been created in the subMounts table.  
1225      * This is to allow sites that want to restrict access to the 
1226      * world to do so.
1227      */
1228         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1229                                                 0, KEY_QUERY_VALUE, &parmKey);
1230         if (code == ERROR_SUCCESS) {
1231         len = sizeof(allSubmount);
1232         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1233                                 (BYTE *) &allSubmount, &len);
1234         if (code != ERROR_SUCCESS) {
1235             allSubmount = 1;
1236         }
1237         RegCloseKey (parmKey);
1238         }
1239
1240         if (allSubmount && _stricmp(shareName, "all") == 0) {
1241                 *pathNamep = NULL;
1242                 return 1;
1243         }
1244
1245     /* In case, the all share is disabled we need to still be able
1246      * to handle ioctl requests 
1247      */
1248         if (_stricmp(shareName, "ioctl$") == 0) {
1249                 *pathNamep = strdup("/.__ioctl__");
1250                 return 1;
1251         }
1252
1253 #ifndef DJGPP
1254     strcpy(sbmtpath, "afsdsbmt.ini");
1255 #else /* DJGPP */
1256     strcpy(sbmtpath, cm_confDir);
1257     strcat(sbmtpath, "/afsdsbmt.ini");
1258 #endif /* !DJGPP */
1259         len = GetPrivateProfileString("AFS Submounts", shareName, "",
1260                                   pathName, sizeof(pathName), sbmtpath);
1261         if (len != 0 && len != sizeof(pathName) - 1) {
1262         /* We can accept either unix or PC style AFS pathnames.  Convert
1263          * Unix-style to PC style here for internal use. 
1264          */
1265         p = pathName;
1266         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1267             p += strlen(cm_mountRoot);  /* skip mount path */
1268         q = p;
1269         while (*q) {
1270             if (*q == '/') *q = '\\';    /* change to \ */
1271             q++;
1272         }
1273
1274         while (1)
1275         {
1276             if (var = smb_stristr(p, VNUserName)) {
1277                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1278                 if (uidp && uidp->unp)
1279                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1280                 else
1281                     smb_subst(p, var, sizeof(VNUserName)," ");
1282                 if (uidp)
1283                     smb_ReleaseUID(uidp);
1284             }
1285             else if (var = smb_stristr(p, VNLCUserName)) 
1286             {
1287                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1288                 if (uidp && uidp->unp)
1289                     strcpy(temp, uidp->unp->name);
1290                 else 
1291                     strcpy(temp, " ");
1292                 _strlwr(temp);
1293                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1294                 if (uidp)
1295                     smb_ReleaseUID(uidp);
1296             }
1297             else if (var = smb_stristr(p, VNComputerName)) 
1298             {
1299                 sizeTemp = sizeof(temp);
1300                 GetComputerName((LPTSTR)temp, &sizeTemp);
1301                 smb_subst(p, var, sizeof(VNComputerName), temp);
1302             }
1303             else if (var = smb_stristr(p, VNLCComputerName)) 
1304             {
1305                 sizeTemp = sizeof(temp);
1306                 GetComputerName((LPTSTR)temp, &sizeTemp);
1307                 _strlwr(temp);
1308                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1309             }
1310             else     
1311                 break;
1312         }
1313         *pathNamep = strdup(p);
1314         return 1;
1315     } 
1316     else /* create  \\<netbiosName>\<cellname>  */
1317     {
1318         char * p = shareName; 
1319         int rw = 0;
1320
1321         if ( *p == '.' ) {
1322             p++;
1323             rw = 1;
1324         }
1325         /* Get the full name for this cell */
1326         code = cm_SearchCellFile(p, temp, 0, 0);
1327 #ifdef AFS_AFSDB_ENV
1328                 if (code && cm_dnsEnabled) {
1329             int ttl;
1330             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1331         }
1332 #endif
1333         /* construct the path */
1334         if (code == 0) {     
1335             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1336             *pathNamep = strdup(strlwr(pathName));
1337             return 1;
1338         }
1339         }
1340     /* failure */
1341     *pathNamep = NULL;
1342     return 0;
1343 }
1344
1345 /* Client-side offline caching policy types */
1346 #define CSC_POLICY_MANUAL 0
1347 #define CSC_POLICY_DOCUMENTS 1
1348 #define CSC_POLICY_PROGRAMS 2
1349 #define CSC_POLICY_DISABLE 3
1350
1351 int smb_FindShareCSCPolicy(char *shareName)
1352 {
1353         DWORD len;
1354         char policy[1024];
1355         char sbmtpath[256];
1356
1357 #ifndef DJGPP
1358         strcpy(sbmtpath, "afsdsbmt.ini");
1359 #else /* DJGPP */
1360         strcpy(sbmtpath, cm_confDir);
1361         strcat(sbmtpath, "/afsdsbmt.ini");
1362 #endif /* !DJGPP */
1363         len = GetPrivateProfileString("CSC Policy", shareName, "",
1364                                       policy, sizeof(policy), sbmtpath);
1365         if (len == 0 || len == sizeof(policy) - 1) {
1366                 return CSC_POLICY_MANUAL;
1367         }
1368         
1369         if (stricmp(policy, "documents") == 0)
1370         {
1371                 return CSC_POLICY_DOCUMENTS;
1372         }
1373         
1374         if (stricmp(policy, "programs") == 0)
1375         {
1376                 return CSC_POLICY_PROGRAMS;
1377         }
1378         
1379         if (stricmp(policy, "disable") == 0)
1380         {
1381                 return CSC_POLICY_DISABLE;
1382         }
1383         
1384         return CSC_POLICY_MANUAL;
1385 }
1386
1387 /* find a dir search structure by cookie value, and return it held.
1388  * Must be called with smb_globalLock held.
1389  */
1390 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1391 {
1392         smb_dirSearch_t *dsp;
1393         
1394         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1395                 if (dsp->cookie == cookie) {
1396                         if (dsp != smb_firstDirSearchp) {
1397                                 /* move to head of LRU queue, too, if we're not already there */
1398                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1399                                         smb_lastDirSearchp = (smb_dirSearch_t *)
1400                                                 osi_QPrev(&dsp->q);
1401                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1402                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1403                                 if (!smb_lastDirSearchp)
1404                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1405                         }
1406                         dsp->refCount++;
1407                         break;
1408                 }
1409         }
1410         return dsp;
1411 }
1412
1413 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1414 {
1415         lock_ObtainWrite(&smb_globalLock);
1416         dsp->flags |= SMB_DIRSEARCH_DELETE;
1417         lock_ReleaseWrite(&smb_globalLock);
1418         lock_ObtainMutex(&dsp->mx);
1419         if(dsp->scp != NULL) {
1420                 lock_ObtainMutex(&dsp->scp->mx);
1421                 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1422                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1423                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1424                     dsp->scp->bulkStatProgress = hones;
1425                 }       
1426                 lock_ReleaseMutex(&dsp->scp->mx);
1427         }       
1428         lock_ReleaseMutex(&dsp->mx);
1429 }
1430
1431 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1432 {
1433         cm_scache_t *scp;
1434         
1435         scp = NULL;
1436
1437         lock_ObtainWrite(&smb_globalLock);
1438         osi_assert(dsp->refCount-- > 0);
1439         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1440                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1441                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1442                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1443                 lock_FinalizeMutex(&dsp->mx);
1444                 scp = dsp->scp;
1445                 free(dsp);
1446         }
1447         lock_ReleaseWrite(&smb_globalLock);
1448
1449         /* do this now to avoid spurious locking hierarchy creation */
1450         if (scp) cm_ReleaseSCache(scp);
1451 }
1452
1453 /* find a dir search structure by cookie value, and return it held */
1454 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1455 {
1456         smb_dirSearch_t *dsp;
1457
1458         lock_ObtainWrite(&smb_globalLock);
1459         dsp = smb_FindDirSearchNL(cookie);
1460         lock_ReleaseWrite(&smb_globalLock);
1461         return dsp;
1462 }
1463
1464 /* GC some dir search entries, in the address space expected by the specific protocol.
1465  * Must be called with smb_globalLock held; release the lock temporarily.
1466  */
1467 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1468 void smb_GCDirSearches(int isV3)
1469 {
1470         smb_dirSearch_t *prevp;
1471         smb_dirSearch_t *tp;
1472         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1473         int victimCount;
1474         int i;
1475         
1476         victimCount = 0;        /* how many have we got so far */
1477         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1478                 /* we'll move tp from queue, so
1479                  * do this early.
1480                  */
1481                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1482                 /* if no one is using this guy, and we're either in the new protocol,
1483                  * or we're in the old one and this is a small enough ID to be useful
1484                  * to the old protocol, GC this guy.
1485                  */
1486                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1487                         /* hold and delete */
1488                         tp->flags |= SMB_DIRSEARCH_DELETE;
1489                         victimsp[victimCount++] = tp;
1490                         tp->refCount++;
1491                 }
1492
1493                 /* don't do more than this */
1494                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1495         }
1496         
1497         /* now release them */
1498         lock_ReleaseWrite(&smb_globalLock);
1499         for(i = 0; i < victimCount; i++) {
1500                 smb_ReleaseDirSearch(victimsp[i]);
1501         }
1502         lock_ObtainWrite(&smb_globalLock);
1503 }
1504
1505 /* function for allocating a dir search entry.  We need these to remember enough context
1506  * since we don't get passed the path from call to call during a directory search.
1507  *
1508  * Returns a held dir search structure, and bumps the reference count on the vnode,
1509  * since it saves a pointer to the vnode.
1510  */
1511 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1512 {
1513         smb_dirSearch_t *dsp;
1514         int counter;
1515         int maxAllowed;
1516
1517         lock_ObtainWrite(&smb_globalLock);
1518         counter = 0;
1519
1520         /* what's the biggest ID allowed in this version of the protocol */
1521         if (isV3) maxAllowed = 65535;
1522         else maxAllowed = 255;
1523
1524         while(1) {
1525                 /* twice so we have enough tries to find guys we GC after one pass;
1526                  * 10 extra is just in case I mis-counted.
1527                  */
1528                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1529                                                                                                         __FILE__, __LINE__);
1530                 if (smb_dirSearchCounter > maxAllowed) {        
1531                         smb_dirSearchCounter = 1;
1532                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
1533                 }       
1534                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1535                 if (dsp) {
1536                         /* don't need to watch for refcount zero and deleted, since
1537                          * we haven't dropped the global lock.
1538                          */
1539                         dsp->refCount--;
1540                         ++smb_dirSearchCounter;
1541                         continue;
1542                 }       
1543                 
1544                 dsp = malloc(sizeof(*dsp));
1545                 memset(dsp, 0, sizeof(*dsp));
1546                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1547                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1548                 dsp->cookie = smb_dirSearchCounter;
1549                 ++smb_dirSearchCounter;
1550                 dsp->refCount = 1;
1551                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1552                 dsp->lastTime = osi_Time();
1553                 break;
1554         }       
1555         lock_ReleaseWrite(&smb_globalLock);
1556         return dsp;
1557 }
1558
1559 static smb_packet_t *GetPacket(void)
1560 {
1561         smb_packet_t *tbp;
1562 #ifdef DJGPP
1563         unsigned int npar, seg, tb_sel;
1564 #endif
1565
1566         lock_ObtainWrite(&smb_globalLock);
1567         tbp = smb_packetFreeListp;
1568     if (tbp) 
1569         smb_packetFreeListp = tbp->nextp;
1570         lock_ReleaseWrite(&smb_globalLock);
1571     if (!tbp) {
1572 #ifndef DJGPP
1573         tbp = calloc(65540,1);
1574 #else /* DJGPP */
1575         tbp = malloc(sizeof(smb_packet_t));
1576 #endif /* !DJGPP */
1577         tbp->magic = SMB_PACKETMAGIC;
1578                 tbp->ncbp = NULL;
1579                 tbp->vcp = NULL;
1580                 tbp->resumeCode = 0;
1581                 tbp->inCount = 0;
1582                 tbp->fid = 0;
1583                 tbp->wctp = NULL;
1584                 tbp->inCom = 0;
1585                 tbp->oddByte = 0;
1586                 tbp->ncb_length = 0;
1587                 tbp->flags = 0;
1588         tbp->spacep = NULL;
1589         
1590 #ifdef DJGPP
1591         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1592         {
1593             signed int retval =
1594                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1595             if (retval == -1) {
1596                 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1597                           npar);
1598                 osi_panic("",__FILE__,__LINE__);
1599             }
1600             else {
1601                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1602                           npar, retval);
1603                 seg = retval;
1604             }
1605         }
1606         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1607         tbp->dos_pkt_sel = tb_sel;
1608 #endif /* DJGPP */
1609         }
1610     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1611
1612     return tbp;
1613 }
1614
1615 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1616 {
1617         smb_packet_t *tbp;
1618         tbp = GetPacket();
1619         memcpy(tbp, pkt, sizeof(smb_packet_t));
1620         tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1621         return tbp;
1622 }
1623
1624 static NCB *GetNCB(void)
1625 {
1626         smb_ncb_t *tbp;
1627     NCB *ncbp;
1628 #ifdef DJGPP
1629     unsigned int npar, seg, tb_sel;
1630 #endif /* DJGPP */
1631
1632         lock_ObtainWrite(&smb_globalLock);
1633         tbp = smb_ncbFreeListp;
1634     if (tbp) 
1635         smb_ncbFreeListp = tbp->nextp;
1636         lock_ReleaseWrite(&smb_globalLock);
1637     if (!tbp) {
1638 #ifndef DJGPP
1639         tbp = calloc(sizeof(*tbp),1);
1640 #else /* DJGPP */
1641         tbp = malloc(sizeof(*tbp));
1642         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1643         {
1644             signed int retval =
1645                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1646             if (retval == -1) {
1647                 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1648                           npar);
1649                 osi_panic("",__FILE__,__LINE__);
1650             } else {
1651                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1652                           npar, retval);
1653                 seg = retval;
1654             }
1655         }
1656         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1657         tbp->dos_ncb_sel = tb_sel;
1658 #endif /* !DJGPP */
1659         tbp->magic = SMB_NCBMAGIC;
1660         }
1661         
1662     osi_assert(tbp->magic == SMB_NCBMAGIC);
1663
1664         memset(&tbp->ncb, 0, sizeof(NCB));
1665     ncbp = &tbp->ncb;
1666 #ifdef DJGPP
1667     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1668 #endif /* DJGPP */
1669     return ncbp;
1670 }
1671
1672 void smb_FreePacket(smb_packet_t *tbp)
1673 {
1674     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1675         
1676     lock_ObtainWrite(&smb_globalLock);
1677         tbp->nextp = smb_packetFreeListp;
1678         smb_packetFreeListp = tbp;
1679         tbp->magic = SMB_PACKETMAGIC;
1680         tbp->ncbp = NULL;
1681         tbp->vcp = NULL;
1682         tbp->resumeCode = 0;
1683         tbp->inCount = 0;
1684         tbp->fid = 0;
1685         tbp->wctp = NULL;
1686         tbp->inCom = 0;
1687         tbp->oddByte = 0;
1688         tbp->ncb_length = 0;
1689         tbp->flags = 0;
1690     lock_ReleaseWrite(&smb_globalLock);
1691 }
1692
1693 static void FreeNCB(NCB *bufferp)
1694 {
1695         smb_ncb_t *tbp;
1696         
1697     tbp = (smb_ncb_t *) bufferp;
1698     osi_assert(tbp->magic == SMB_NCBMAGIC);
1699         
1700     lock_ObtainWrite(&smb_globalLock);
1701         tbp->nextp = smb_ncbFreeListp;
1702         smb_ncbFreeListp = tbp;
1703     lock_ReleaseWrite(&smb_globalLock);
1704 }
1705
1706 /* get a ptr to the data part of a packet, and its count */
1707 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1708 {
1709     int parmBytes;
1710     int dataBytes;
1711     unsigned char *afterParmsp;
1712
1713     parmBytes = *smbp->wctp << 1;
1714         afterParmsp = smbp->wctp + parmBytes + 1;
1715         
1716     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1717     if (nbytesp) *nbytesp = dataBytes;
1718         
1719         /* don't forget to skip the data byte count, since it follows
1720      * the parameters; that's where the "2" comes from below.
1721      */
1722     return (unsigned char *) (afterParmsp + 2);
1723 }
1724
1725 /* must set all the returned parameters before playing around with the
1726  * data region, since the data region is located past the end of the
1727  * variable number of parameters.
1728  */
1729 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1730 {
1731         unsigned char *afterParmsp;
1732
1733         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1734         
1735         *afterParmsp++ = dsize & 0xff;
1736         *afterParmsp = (dsize>>8) & 0xff;
1737 }
1738
1739 /* return the parm'th parameter in the smbp packet */
1740 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1741 {
1742         int parmCount;
1743         unsigned char *parmDatap;
1744
1745         parmCount = *smbp->wctp;
1746
1747         if (parm >= parmCount) {
1748 #ifndef DJGPP
1749         HANDLE h;
1750                 char *ptbuf[1];
1751                 char s[100];
1752                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1753                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1754                                 parm, parmCount, smbp->ncb_length);
1755                 ptbuf[0] = s;
1756                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1757                                         1, smbp->ncb_length, ptbuf, smbp);
1758                 DeregisterEventSource(h);
1759 #else /* DJGPP */
1760                 char s[100];
1761
1762                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1763                                 parm, parmCount, smbp->ncb_length);
1764                 osi_Log0(smb_logp, s);
1765 #endif /* !DJGPP */
1766                 osi_panic(s, __FILE__, __LINE__);
1767         }
1768         parmDatap = smbp->wctp + (2*parm) + 1;
1769         
1770         return parmDatap[0] + (parmDatap[1] << 8);
1771 }
1772
1773 /* return the parm'th parameter in the smbp packet */
1774 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1775 {
1776         int parmCount;
1777         unsigned char *parmDatap;
1778
1779         parmCount = *smbp->wctp;
1780
1781         if (parm * 2 + offset >= parmCount * 2) {
1782 #ifndef DJGPP
1783                 HANDLE h;
1784                 char *ptbuf[1];
1785                 char s[100];
1786                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1787                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1788                                 parm, offset, parmCount, smbp->ncb_length);
1789                 ptbuf[0] = s;
1790                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1791                                         1, smbp->ncb_length, ptbuf, smbp);
1792                 DeregisterEventSource(h);
1793 #else /* DJGPP */
1794                 char s[100];
1795                 
1796                 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1797                                 "ncb len %d",
1798                                  parm, offset, parmCount, smbp->ncb_length);
1799                 osi_Log0(smb_logp, s);
1800 #endif /* !DJGPP */
1801
1802                 osi_panic(s, __FILE__, __LINE__);
1803         }
1804         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1805         
1806         return parmDatap[0] + (parmDatap[1] << 8);
1807 }
1808
1809 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1810 {
1811         char *parmDatap;
1812
1813         /* make sure we have enough slots */
1814         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1815         
1816         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1817         *parmDatap++ = parmValue & 0xff;
1818         *parmDatap = (parmValue>>8) & 0xff;
1819 }
1820
1821 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1822 {
1823         char *parmDatap;
1824
1825         /* make sure we have enough slots */
1826         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1827
1828         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1829         *parmDatap++ = parmValue & 0xff;
1830         *parmDatap++ = (parmValue>>8) & 0xff;
1831         *parmDatap++ = (parmValue>>16) & 0xff;
1832         *parmDatap++ = (parmValue>>24) & 0xff;
1833 }
1834
1835 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1836 {
1837         char *parmDatap;
1838         int i;
1839
1840         /* make sure we have enough slots */
1841         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1842
1843         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1844         for (i=0; i<8; i++)
1845                 *parmDatap++ = *parmValuep++;
1846 }
1847
1848 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1849 {
1850         char *parmDatap;
1851
1852         /* make sure we have enough slots */
1853         if (*smbp->wctp <= slot) {
1854                 if (smbp->oddByte) {
1855                         smbp->oddByte = 0;
1856                         *smbp->wctp = slot+1;
1857                 } else
1858                         smbp->oddByte = 1;
1859         }
1860
1861         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1862         *parmDatap++ = parmValue & 0xff;
1863 }
1864
1865 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1866 {
1867         char *lastSlashp;
1868         
1869         lastSlashp = strrchr(inPathp, '\\');
1870         if (lastComponentp)
1871                 *lastComponentp = lastSlashp;
1872         if (lastSlashp) {
1873                 while (1) {
1874                         if (inPathp == lastSlashp) 
1875                                 break;
1876                         *outPathp++ = *inPathp++;
1877                 }
1878                 *outPathp++ = 0;
1879         }
1880         else {
1881                 *outPathp++ = 0;
1882         }
1883 }
1884
1885 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1886 {
1887         if (*inp++ != 0x4) 
1888                 return NULL;
1889         if (chainpp) {
1890                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1891         }
1892         return inp;
1893 }
1894
1895 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1896 {
1897         int tlen;
1898
1899         if (*inp++ != 0x5) 
1900                 return NULL;
1901         tlen = inp[0] + (inp[1]<<8);
1902         inp += 2;               /* skip length field */
1903         
1904         if (chainpp) {
1905                 *chainpp = inp + tlen;
1906         }
1907         
1908         if (lengthp) 
1909                 *lengthp = tlen;
1910         
1911         return inp;
1912 }       
1913
1914 /* format a packet as a response */
1915 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1916 {
1917         smb_t *outp;
1918         smb_t *inSmbp;
1919
1920         outp = (smb_t *) op;
1921         
1922         /* zero the basic structure through the smb_wct field, and zero the data
1923          * size field, assuming that wct stays zero; otherwise, you have to 
1924          * explicitly set the data size field, too.
1925          */
1926         inSmbp = (smb_t *) inp;
1927         memset(outp, 0, sizeof(smb_t)+2);
1928         outp->id[0] = 0xff;
1929         outp->id[1] = 'S';
1930         outp->id[2] = 'M';
1931         outp->id[3] = 'B';
1932         if (inp) {
1933                 outp->com = inSmbp->com;
1934                 outp->tid = inSmbp->tid;
1935                 outp->pid = inSmbp->pid;
1936                 outp->uid = inSmbp->uid;
1937                 outp->mid = inSmbp->mid;
1938                 outp->res[0] = inSmbp->res[0];
1939                 outp->res[1] = inSmbp->res[1];
1940                 op->inCom = inSmbp->com;
1941         }
1942         outp->reb = 0x80;       /* SERVER_RESP */
1943         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
1944
1945         /* copy fields in generic packet area */
1946         op->wctp = &outp->wct;
1947 }
1948
1949 /* send a (probably response) packet; vcp tells us to whom to send it.
1950  * we compute the length by looking at wct and bcc fields.
1951  */
1952 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1953 {
1954         NCB *ncbp;
1955         int extra;
1956         long code = 0;
1957         unsigned char *tp;
1958         int localNCB = 0;
1959 #ifdef DJGPP
1960         dos_ptr dos_ncb;
1961 #endif /* DJGPP */
1962         
1963         ncbp = inp->ncbp;
1964         if (ncbp == NULL) {
1965                 ncbp = GetNCB();
1966                 localNCB = 1;
1967         }
1968 #ifdef DJGPP
1969         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1970 #endif /* DJGPP */
1971  
1972         memset((char *)ncbp, 0, sizeof(NCB));
1973
1974         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
1975         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
1976         extra += tp[0] + (tp[1]<<8);
1977         extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);   /* distance to last wct field */
1978         extra += 3;                     /* wct and length fields */
1979         
1980         ncbp->ncb_length = extra;       /* bytes to send */
1981         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
1982         ncbp->ncb_lana_num = vcp->lana;
1983         ncbp->ncb_command = NCBSEND;    /* op means send data */
1984 #ifndef DJGPP
1985         ncbp->ncb_buffer = (char *) inp;/* packet */
1986         code = Netbios(ncbp);
1987 #else /* DJGPP */
1988         ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1989         ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1990
1991         /* copy header information from virtual to DOS address space */
1992         dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1993         code = Netbios(ncbp, dos_ncb);
1994 #endif /* !DJGPP */
1995         
1996         if (code != 0)
1997                 osi_Log1(smb_logp, "SendPacket failure code %d", code);
1998
1999         if (localNCB)
2000                 FreeNCB(ncbp);
2001 }
2002
2003 void smb_MapNTError(long code, unsigned long *NTStatusp)
2004 {
2005         unsigned long NTStatus;
2006
2007         /* map CM_ERROR_* errors to NT 32-bit status codes */
2008         if (code == CM_ERROR_NOSUCHCELL) {
2009                 NTStatus = 0xC000000FL; /* No such file */
2010         }
2011         else if (code == CM_ERROR_NOSUCHVOLUME) {
2012                 NTStatus = 0xC000000FL; /* No such file */
2013         }
2014         else if (code == CM_ERROR_TIMEDOUT) {
2015                 NTStatus = 0xC00000CFL; /* Sharing Paused */
2016         }
2017         else if (code == CM_ERROR_RETRY) {
2018                 NTStatus = 0xC000022DL; /* Retry */
2019         }
2020         else if (code == CM_ERROR_NOACCESS) {
2021                 NTStatus = 0xC0000022L; /* Access denied */
2022         }
2023         else if (code == CM_ERROR_READONLY) {
2024                 NTStatus = 0xC00000A2L; /* Write protected */
2025         }       
2026         else if (code == CM_ERROR_NOSUCHFILE) {
2027                 NTStatus = 0xC000000FL; /* No such file */
2028         }
2029         else if (code == CM_ERROR_NOSUCHPATH) {
2030                 NTStatus = 0xC000003AL; /* Object path not found */
2031         }               
2032         else if (code == CM_ERROR_TOOBIG) {
2033                 NTStatus = 0xC000007BL; /* Invalid image format */
2034         }
2035         else if (code == CM_ERROR_INVAL) {
2036                 NTStatus = 0xC000000DL; /* Invalid parameter */
2037         }
2038         else if (code == CM_ERROR_BADFD) {
2039                 NTStatus = 0xC0000008L; /* Invalid handle */
2040         }
2041         else if (code == CM_ERROR_BADFDOP) {
2042                 NTStatus = 0xC0000022L; /* Access denied */
2043         }
2044         else if (code == CM_ERROR_EXISTS) {
2045                 NTStatus = 0xC0000035L; /* Object name collision */
2046         }
2047         else if (code == CM_ERROR_NOTEMPTY) {
2048                 NTStatus = 0xC0000101L; /* Directory not empty */
2049         }       
2050         else if (code == CM_ERROR_CROSSDEVLINK) {
2051                 NTStatus = 0xC00000D4L; /* Not same device */
2052         }
2053         else if (code == CM_ERROR_NOTDIR) {
2054                 NTStatus = 0xC0000103L; /* Not a directory */
2055         }
2056         else if (code == CM_ERROR_ISDIR) {
2057                 NTStatus = 0xC00000BAL; /* File is a directory */
2058         }
2059         else if (code == CM_ERROR_BADOP) {
2060                 NTStatus = 0xC09820FFL; /* SMB no support */
2061         }
2062         else if (code == CM_ERROR_BADSHARENAME) {
2063                 NTStatus = 0xC00000CCL; /* Bad network name */
2064         }
2065         else if (code == CM_ERROR_NOIPC) {
2066 #ifdef COMMENT
2067                 NTStatus = 0xC0000022L; /* Access Denied */
2068 #else
2069         NTStatus = 0xC000013DL; /* Remote Resources */
2070 #endif
2071         }
2072         else if (code == CM_ERROR_CLOCKSKEW) {
2073                 NTStatus = 0xC0000133L; /* Time difference at DC */
2074         }
2075         else if (code == CM_ERROR_BADTID) {
2076                 NTStatus = 0xC0982005L; /* SMB bad TID */
2077         }
2078         else if (code == CM_ERROR_USESTD) {
2079                 NTStatus = 0xC09820FBL; /* SMB use standard */
2080         }
2081         else if (code == CM_ERROR_QUOTA) {
2082                 NTStatus = 0xC0000044L; /* Quota exceeded */
2083         }
2084         else if (code == CM_ERROR_SPACE) {
2085                 NTStatus = 0xC000007FL; /* Disk full */
2086         }
2087         else if (code == CM_ERROR_ATSYS) {
2088                 NTStatus = 0xC0000033L; /* Object name invalid */
2089         }
2090         else if (code == CM_ERROR_BADNTFILENAME) {
2091                 NTStatus = 0xC0000033L; /* Object name invalid */
2092         }
2093         else if (code == CM_ERROR_WOULDBLOCK) {
2094                 NTStatus = 0xC0000055L; /* Lock not granted */
2095         }
2096         else if (code == CM_ERROR_PARTIALWRITE) {
2097                 NTStatus = 0xC000007FL; /* Disk full */
2098         }
2099         else if (code == CM_ERROR_BUFFERTOOSMALL) {
2100                 NTStatus = 0xC0000023L; /* Buffer too small */
2101         }
2102     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2103 #ifdef COMMENT
2104                 NTStatus = 0xC000049CL; /* Potential file found */
2105 #else
2106                 NTStatus = 0xC0000035L; /* Object name collision */
2107 #endif
2108     }
2109         else {
2110                 NTStatus = 0xC0982001L; /* SMB non-specific error */
2111         }
2112
2113         *NTStatusp = NTStatus;
2114         osi_Log2(smb_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2115 }
2116
2117 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2118         unsigned char *classp)
2119 {
2120         unsigned char class;
2121         unsigned short error;
2122
2123         /* map CM_ERROR_* errors to SMB errors */
2124         if (code == CM_ERROR_NOSUCHCELL) {
2125                 class = 1;
2126                 error = 3;      /* bad path */
2127         }
2128         else if (code == CM_ERROR_NOSUCHVOLUME) {
2129                 class = 1;
2130                 error = 3;      /* bad path */
2131         }
2132         else if (code == CM_ERROR_TIMEDOUT) {
2133                 class = 2;
2134                 error = 81;     /* server is paused */
2135         }
2136         else if (code == CM_ERROR_RETRY) {
2137                 class = 2;      /* shouldn't happen */
2138                 error = 1;
2139         }
2140         else if (code == CM_ERROR_NOACCESS) {
2141                 class = 2;
2142                 error = 4;      /* bad access */
2143         }
2144         else if (code == CM_ERROR_READONLY) {
2145                 class = 3;
2146                 error = 19;     /* read only */
2147         }
2148         else if (code == CM_ERROR_NOSUCHFILE) {
2149                 class = 1;
2150                 error = 2;      /* ENOENT! */
2151         }
2152         else if (code == CM_ERROR_NOSUCHPATH) {
2153                 class = 1;
2154                 error = 3;      /* Bad path */
2155         }
2156         else if (code == CM_ERROR_TOOBIG) {
2157                 class = 1;
2158                 error = 11;     /* bad format */
2159         }
2160         else if (code == CM_ERROR_INVAL) {
2161                 class = 2;      /* server non-specific error code */
2162                 error = 1;
2163         }
2164         else if (code == CM_ERROR_BADFD) {
2165                 class = 1;
2166                 error = 6;      /* invalid file handle */
2167         }
2168         else if (code == CM_ERROR_BADFDOP) {
2169                 class = 1;      /* invalid op on FD */
2170                 error = 5;
2171         }
2172         else if (code == CM_ERROR_EXISTS) {
2173                 class = 1;
2174                 error = 80;     /* file already exists */
2175         }
2176         else if (code == CM_ERROR_NOTEMPTY) {
2177                 class = 1;
2178                 error = 5;      /* delete directory not empty */
2179         }
2180         else if (code == CM_ERROR_CROSSDEVLINK) {
2181                 class = 1;
2182                 error = 17;     /* EXDEV */
2183         }
2184         else if (code == CM_ERROR_NOTDIR) {
2185                 class = 1;      /* bad path */
2186                 error = 3;
2187         }
2188         else if (code == CM_ERROR_ISDIR) {
2189                 class = 1;      /* access denied; DOS doesn't have a good match */
2190                 error = 5;
2191         }
2192         else if (code == CM_ERROR_BADOP) {
2193                 class = 2;
2194                 error = 65535;
2195         }
2196         else if (code == CM_ERROR_BADSHARENAME) {
2197                 class = 2;
2198                 error = 6;
2199         }
2200         else if (code == CM_ERROR_NOIPC) {
2201                 class = 2;
2202                 error = 4; /* bad access */
2203         }
2204         else if (code == CM_ERROR_CLOCKSKEW) {
2205                 class = 1;      /* invalid function */
2206                 error = 1;
2207         }
2208         else if (code == CM_ERROR_BADTID) {
2209                 class = 2;
2210                 error = 5;
2211         }
2212         else if (code == CM_ERROR_USESTD) {
2213                 class = 2;
2214                 error = 251;
2215         }
2216         else if (code == CM_ERROR_REMOTECONN) {
2217                 class = 2;
2218                 error = 82;
2219         }
2220         else if (code == CM_ERROR_QUOTA) {
2221                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2222                         class = 3;
2223                         error = 39;     /* disk full */
2224                 }
2225                 else {
2226                         class = 1;
2227                         error = 5;      /* access denied */
2228                 }
2229         }
2230         else if (code == CM_ERROR_SPACE) {
2231                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2232                         class = 3;
2233                         error = 39;     /* disk full */
2234                 }
2235                 else {
2236                         class = 1;
2237                         error = 5;      /* access denied */
2238                 }
2239         }
2240         else if (code == CM_ERROR_PARTIALWRITE) {
2241                 class = 3;
2242                 error = 39;     /* disk full */
2243         }
2244         else if (code == CM_ERROR_ATSYS) {
2245                 class = 1;
2246                 error = 2;      /* ENOENT */
2247         }
2248         else if (code == CM_ERROR_WOULDBLOCK) {
2249                 class = 1;
2250                 error = 33;     /* lock conflict */
2251         }
2252         else if (code == CM_ERROR_NOFILES) {
2253                 class = 1;
2254                 error = 18;     /* no files in search */
2255         }
2256         else if (code == CM_ERROR_RENAME_IDENTICAL) {
2257                 class = 1;
2258                 error = 183;     /* Samba uses this */
2259         }
2260         else {
2261                 class = 2;
2262                 error = 1;
2263         }
2264
2265         *scodep = error;
2266         *classp = class;
2267         osi_Log3(smb_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2268 }
2269
2270 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2271 {
2272         return CM_ERROR_BADOP;
2273 }
2274
2275 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2276 {
2277         unsigned short EchoCount, i;
2278         char *data, *outdata;
2279         int dataSize;
2280
2281         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2282
2283         for (i=1; i<=EchoCount; i++) {
2284             data = smb_GetSMBData(inp, &dataSize);
2285             smb_SetSMBParm(outp, 0, i);
2286             smb_SetSMBDataLength(outp, dataSize);
2287             outdata = smb_GetSMBData(outp, NULL);
2288             memcpy(outdata, data, dataSize);
2289             smb_SendPacket(vcp, outp);
2290         }
2291
2292         return 0;
2293 }
2294
2295 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2296 {
2297         osi_hyper_t offset;
2298         long count, minCount, finalCount;
2299         unsigned short fd;
2300         smb_fid_t *fidp;
2301         long code = 0;
2302         cm_user_t *userp = NULL;
2303     NCB *ncbp;
2304     int rc;
2305 #ifndef DJGPP
2306     char *rawBuf = NULL;
2307 #else
2308     dos_ptr rawBuf = NULL;
2309     dos_ptr dos_ncb;
2310 #endif /* DJGPP */
2311
2312         rawBuf = NULL;
2313         finalCount = 0;
2314
2315         fd = smb_GetSMBParm(inp, 0);
2316         count = smb_GetSMBParm(inp, 3);
2317         minCount = smb_GetSMBParm(inp, 4);
2318         offset.HighPart = 0;    /* too bad */
2319         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2320
2321         osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2322              fd, offset.LowPart, count);
2323
2324         fidp = smb_FindFID(vcp, fd, 0);
2325         if (!fidp)
2326                 goto send1;
2327
2328         lock_ObtainMutex(&smb_RawBufLock);
2329         if (smb_RawBufs) {
2330                 /* Get a raw buf, from head of list */
2331                 rawBuf = smb_RawBufs;
2332 #ifndef DJGPP
2333                 smb_RawBufs = *(char **)smb_RawBufs;
2334 #else /* DJGPP */
2335         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2336 #endif /* !DJGPP */
2337         }
2338         lock_ReleaseMutex(&smb_RawBufLock);
2339         if (!rawBuf)
2340                 goto send1a;
2341
2342     if (fidp->flags & SMB_FID_IOCTL)
2343     {
2344 #ifndef DJGPP
2345         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2346 #else
2347         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2348 #endif
2349         if (rawBuf) {
2350             /* Give back raw buffer */
2351             lock_ObtainMutex(&smb_RawBufLock);
2352 #ifndef DJGPP
2353             *((char **) rawBuf) = smb_RawBufs;
2354 #else /* DJGPP */
2355             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2356 #endif /* !DJGPP */
2357             
2358             smb_RawBufs = rawBuf;
2359             lock_ReleaseMutex(&smb_RawBufLock);
2360         }
2361
2362         smb_ReleaseFID(fidp);
2363         return rc;
2364     }
2365         
2366     userp = smb_GetUser(vcp, inp);
2367
2368 #ifndef DJGPP
2369         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2370 #else /* DJGPP */
2371     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2372     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2373                         userp, &finalCount, TRUE /* rawFlag */);
2374 #endif /* !DJGPP */
2375
2376         if (code != 0)
2377                 goto send;
2378
2379   send:
2380     cm_ReleaseUser(userp);
2381
2382   send1a:
2383         smb_ReleaseFID(fidp);
2384
2385   send1:
2386         ncbp = outp->ncbp;
2387 #ifdef DJGPP
2388     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2389 #endif /* DJGPP */
2390         memset((char *)ncbp, 0, sizeof(NCB));
2391
2392         ncbp->ncb_length = (unsigned short) finalCount;
2393         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2394         ncbp->ncb_lana_num = vcp->lana;
2395         ncbp->ncb_command = NCBSEND;
2396         ncbp->ncb_buffer = rawBuf;
2397
2398 #ifndef DJGPP
2399         code = Netbios(ncbp);
2400 #else /* DJGPP */
2401         code = Netbios(ncbp, dos_ncb);
2402 #endif /* !DJGPP */
2403         if (code != 0)
2404                 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2405
2406         if (rawBuf) {
2407                 /* Give back raw buffer */
2408                 lock_ObtainMutex(&smb_RawBufLock);
2409 #ifndef DJGPP
2410                 *((char **) rawBuf) = smb_RawBufs;
2411 #else /* DJGPP */
2412         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2413 #endif /* !DJGPP */
2414
2415                 smb_RawBufs = rawBuf;
2416                 lock_ReleaseMutex(&smb_RawBufLock);
2417         }
2418
2419         return 0;
2420 }
2421
2422 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2423 {
2424         return 0;
2425 }
2426
2427 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2428 {
2429         return 0;
2430 }
2431
2432 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2433 {
2434         char *namep;
2435         int coreProtoIndex;
2436         int v3ProtoIndex;
2437         int NTProtoIndex;
2438         int protoIndex;                 /* index we're using */
2439         int namex;
2440         int dbytes;
2441         int entryLength;
2442         int tcounter;
2443         char protocol_array[10][1024]; /* protocol signature of the client */
2444
2445         
2446         osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2447                          ongoingOps - 1);
2448         if (!isGateway) {
2449                 if (active_vcp) {
2450                         DWORD now = GetCurrentTime();
2451                         if (now - last_msg_time >= 30000
2452                                 && now - last_msg_time <= 90000) {
2453                                 osi_Log1(smb_logp,
2454                                                  "Setting dead_vcp %x", active_vcp);
2455                 if (dead_vcp) {
2456                     smb_ReleaseVC(dead_vcp);
2457                     osi_Log1(smb_logp,
2458                               "Previous dead_vcp %x", dead_vcp);
2459                 }
2460                 smb_HoldVC(active_vcp);
2461                                 dead_vcp = active_vcp;
2462                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2463                         }
2464                 }
2465         }
2466
2467         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2468
2469         namep = smb_GetSMBData(inp, &dbytes);
2470         namex = 0;
2471         tcounter = 0;
2472         coreProtoIndex = -1;            /* not found */
2473         v3ProtoIndex = -1;
2474         NTProtoIndex = -1;
2475         while(namex < dbytes) {
2476                 osi_Log1(smb_logp, "Protocol %s",
2477                                  osi_LogSaveString(smb_logp, namep+1));
2478                 strcpy(protocol_array[tcounter], namep+1);
2479
2480                 /* namep points at the first protocol, or really, a 0x02
2481                  * byte preceding the null-terminated ASCII name.
2482                  */
2483                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2484                         coreProtoIndex = tcounter;
2485                 }       
2486                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2487                         v3ProtoIndex = tcounter;
2488                 }
2489                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2490                         NTProtoIndex = tcounter;
2491                 }
2492
2493                 /* compute size of protocol entry */
2494                 entryLength = strlen(namep+1);
2495         entryLength += 2;       /* 0x02 bytes and null termination */
2496                 
2497         /* advance over this protocol entry */
2498                 namex += entryLength;
2499         namep += entryLength;
2500         tcounter++;             /* which proto entry we're looking at */
2501         }
2502 #ifndef NOMOREFILESFIX
2503         /* 
2504          * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2505          * the client is running by reading the protocol signature.
2506          * ie. the order in which it sends us the protocol list.
2507          *
2508          * Special handling for Windows 2000 clients (defect 11765 )
2509      * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2510          */
2511         if (tcounter == 6) {
2512                 int i = 0;
2513                 smb_t *ip = (smb_t *) inp;
2514                 smb_t *op = (smb_t *) outp;
2515
2516                 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2517                          (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2518                          (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2519                          (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2520                          (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2521                          (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2522                         isWindows2000 = TRUE;
2523                         osi_Log0(smb_logp, "Looks like a Windows 2000 client");
2524                         /* 
2525                          * HACK: for now - just negotiate a lower protocol till we 
2526                          * figure out which flag/flag2 or some other field 
2527                          * (capabilities maybe?) to set in order for this to work
2528                          * correctly with Windows 2000 clients (defect 11765)
2529                          */
2530                         NTProtoIndex = -1;
2531                         /* Things to try (after looking at tcpdump output could be
2532                          * setting flags and flags2 to 0x98 and 0xc853 like this
2533                          * op->reb = 0x98; op->flg2 = 0xc853;
2534                          * osi_Log2(smb_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2535                          */
2536                 }       
2537         }       
2538 #endif /* NOMOREFILESFIX */
2539
2540         if (NTProtoIndex != -1) {
2541                 protoIndex = NTProtoIndex;
2542                 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2543         }
2544         else if (v3ProtoIndex != -1) {
2545                 protoIndex = v3ProtoIndex;
2546                 vcp->flags |= SMB_VCFLAG_USEV3;
2547         }       
2548         else if (coreProtoIndex != -1) {
2549                 protoIndex = coreProtoIndex;
2550                 vcp->flags |= SMB_VCFLAG_USECORE;
2551         }       
2552         else protoIndex = -1;
2553
2554         if (protoIndex == -1)
2555                 return CM_ERROR_INVAL;
2556         else if (NTProtoIndex != -1) {
2557                 smb_SetSMBParm(outp, 0, protoIndex);
2558         smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2559         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2560         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2561         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2562                 smb_SetSMBParmLong(outp, 5, 65536);     /* raw buffer size */
2563         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2564         smb_SetSMBParm(outp, 8, 1);
2565                 /* 
2566                  * Tried changing the capabilities to support for W2K - defect 117695
2567                  * Maybe something else needs to be changed here?
2568                  */
2569                 /*
2570                   if (isWindows2000) 
2571                   smb_SetSMBParmLong(outp, 9, 0x43fd);
2572                   else 
2573                   smb_SetSMBParmLong(outp, 9, 0x251);
2574                   */
2575                 /* Capabilities: *
2576                  * 32-bit error codes *
2577                  * and NT Find *
2578                  * and NT SMB's *
2579                  * and raw mode */
2580                 smb_SetSMBParmLong(outp, 9, 0x251);     
2581                 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2582                 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2583                 smb_SetSMBParm(outp, 15, 0);    /* XXX server tzone: do we need? */
2584                 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2585                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2586         }
2587         else if (v3ProtoIndex != -1) {
2588                 smb_SetSMBParm(outp, 0, protoIndex);
2589                 smb_SetSMBParm(outp, 1, 0);     /* share level security, no passwd encrypt */
2590                 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2591                 smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2592                 smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2593                 smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2594                 smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2595                 smb_SetSMBParm(outp, 7, 1);
2596                 smb_SetSMBParm(outp, 8, 0);     /* XXX server time: do we need? */
2597                 smb_SetSMBParm(outp, 9, 0);     /* XXX server date: do we need? */
2598                 smb_SetSMBParm(outp, 10, 0);    /* XXX server tzone: do we need? */
2599                 smb_SetSMBParm(outp, 11, 0);    /* resvd */
2600                 smb_SetSMBParm(outp, 12, 0);    /* resvd */
2601                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2602         }
2603         else if (coreProtoIndex != -1) {
2604                 smb_SetSMBParm(outp, 0, protoIndex);
2605                 smb_SetSMBDataLength(outp, 0);
2606         }
2607         return 0;
2608 }
2609
2610 void smb_Daemon(void *parmp)
2611 {
2612         int count = 0;
2613
2614         while(1) {
2615                 count++;
2616                 thrd_Sleep(10000);
2617                 if ((count % 360) == 0)         /* every hour */
2618                         smb_CalculateNowTZ();
2619                 /* XXX GC dir search entries */
2620         }
2621 }
2622
2623 void smb_WaitingLocksDaemon()
2624 {
2625         smb_waitingLock_t *wL, *nwL;
2626         int first;
2627         smb_vc_t *vcp;
2628         smb_packet_t *inp, *outp;
2629         NCB *ncbp;
2630         long code = 0;
2631
2632         while(1) {
2633                 lock_ObtainWrite(&smb_globalLock);
2634                 nwL = smb_allWaitingLocks;
2635                 if (nwL == NULL) {
2636                         osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2637                         thrd_Sleep(1000);
2638                         continue;
2639                 }
2640                 else first = 1;
2641                 do {
2642                         if (first)
2643                                 first = 0;
2644                         else
2645                                 lock_ObtainWrite(&smb_globalLock);
2646                         wL = nwL;
2647                         nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2648                         lock_ReleaseWrite(&smb_globalLock);
2649                         code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2650                                                                 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2651                         if (code == CM_ERROR_WOULDBLOCK) {
2652                                 /* no progress */
2653                                 if (wL->timeRemaining != 0xffffffff
2654                                     && (wL->timeRemaining -= 1000) < 0)
2655                                         goto endWait;
2656                                 continue;
2657                         }
2658                   endWait:
2659                         vcp = wL->vcp;
2660                         inp = wL->inp;
2661                         outp = wL->outp;
2662                         ncbp = GetNCB();
2663                         ncbp->ncb_length = inp->ncb_length;
2664                         inp->spacep = cm_GetSpace();
2665
2666                         /* Remove waitingLock from list */
2667                         lock_ObtainWrite(&smb_globalLock);
2668                         osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2669                                     &wL->q);
2670                         lock_ReleaseWrite(&smb_globalLock);
2671
2672                         /* Resume packet processing */
2673                         if (code == 0)
2674                                 smb_SetSMBDataLength(outp, 0);
2675                         outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2676                         outp->resumeCode = code;
2677                         outp->ncbp = ncbp;
2678                         smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2679
2680                         /* Clean up */
2681                         cm_FreeSpace(inp->spacep);
2682                         smb_FreePacket(inp);
2683                         smb_FreePacket(outp);
2684                         FreeNCB(ncbp);
2685                         free(wL);
2686                 } while (nwL);
2687                 thrd_Sleep(1000);
2688         }
2689 }
2690
2691 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2692 {
2693         osi_Log0(smb_logp, "SMB receive get disk attributes");
2694
2695         smb_SetSMBParm(outp, 0, 32000);
2696         smb_SetSMBParm(outp, 1, 64);
2697         smb_SetSMBParm(outp, 2, 1024);
2698         smb_SetSMBParm(outp, 3, 30000);
2699         smb_SetSMBParm(outp, 4, 0);
2700         smb_SetSMBDataLength(outp, 0);
2701         return 0;
2702 }
2703
2704 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2705 {
2706         smb_tid_t *tidp;
2707         unsigned short newTid;
2708         char shareName[256];
2709         char *sharePath;
2710         int shareFound;
2711         char *tp;
2712         char *pathp;
2713         char *passwordp;
2714         cm_user_t *userp;
2715
2716         osi_Log0(smb_logp, "SMB receive tree connect");
2717
2718         /* parse input parameters */
2719         tp = smb_GetSMBData(inp, NULL);
2720         pathp = smb_ParseASCIIBlock(tp, &tp);
2721         passwordp = smb_ParseASCIIBlock(tp, &tp);
2722         tp = strrchr(pathp, '\\');
2723         if (!tp)
2724                 return CM_ERROR_BADSMB;
2725         strcpy(shareName, tp+1);
2726
2727         userp = smb_GetUser(vcp, inp);
2728
2729         lock_ObtainMutex(&vcp->mx);
2730         newTid = vcp->tidCounter++;
2731         lock_ReleaseMutex(&vcp->mx);
2732         
2733         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2734         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2735         if (!shareFound) {
2736                 smb_ReleaseTID(tidp);
2737                 return CM_ERROR_BADSHARENAME;
2738         }
2739         lock_ObtainMutex(&tidp->mx);
2740         tidp->userp = userp;
2741         tidp->pathname = sharePath;
2742         lock_ReleaseMutex(&tidp->mx);
2743         smb_ReleaseTID(tidp);
2744
2745         smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2746         smb_SetSMBParm(rsp, 1, newTid);
2747         smb_SetSMBDataLength(rsp, 0);
2748
2749         osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2750         return 0;
2751 }
2752
2753 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2754 {
2755         int tlen;
2756
2757         if (*inp++ != 0x1) return NULL;
2758         tlen = inp[0] + (inp[1]<<8);
2759         inp += 2;               /* skip length field */
2760         
2761         if (chainpp) {
2762                 *chainpp = inp + tlen;
2763         }       
2764         
2765         if (lengthp) *lengthp = tlen;
2766         
2767         return inp;
2768 }
2769
2770 /* set maskp to the mask part of the incoming path.
2771  * Mask is 11 bytes long (8.3 with the dot elided).
2772  * Returns true if succeeds with a valid name, otherwise it does
2773  * its best, but returns false.
2774  */
2775 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2776 {
2777         char *tp;
2778         char *up;
2779         int i;
2780         int tc;
2781         int valid8Dot3;
2782
2783         /* starts off valid */
2784         valid8Dot3 = 1;
2785
2786         /* mask starts out all blanks */
2787         memset(maskp, ' ', 11);
2788
2789         /* find last backslash, or use whole thing if there is none */
2790         tp = strrchr(pathp, '\\');
2791         if (!tp) tp = pathp;
2792         else tp++;      /* skip slash */
2793         
2794         up = maskp;
2795
2796         /* names starting with a dot are illegal */
2797         if (*tp == '.') valid8Dot3 = 0;
2798
2799     for(i=0;; i++) {
2800                 tc = *tp++;
2801         if (tc == 0) return valid8Dot3;
2802         if (tc == '.' || tc == '"') break;
2803         if (i < 8) *up++ = tc;
2804         else valid8Dot3 = 0;
2805     }
2806         
2807     /* if we get here, tp point after the dot */
2808     up = maskp+8;       /* ext goes here */
2809     for(i=0;;i++) {
2810         tc = *tp++;
2811         if (tc == 0) 
2812                         return valid8Dot3;
2813
2814         /* too many dots */
2815         if (tc == '.' || tc == '"') 
2816                         valid8Dot3 = 0;
2817
2818         /* copy extension if not too long */
2819         if (i < 3) 
2820                         *up++ = tc;
2821         else 
2822                         valid8Dot3 = 0;
2823     }   
2824
2825     /* unreachable */
2826 }
2827
2828 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2829 {
2830         char umask[11];
2831         int valid;
2832         int i;
2833         char tc1;
2834         char tc2;
2835         char *tp1;
2836         char *tp2;
2837
2838         /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2839
2840         valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2841         if (!valid) 
2842                 return 0;
2843  
2844         /* otherwise, we have a valid 8.3 name; see if we have a match,
2845          * treating '?' as a wildcard in maskp (but not in the file name).
2846          */
2847         tp1 = umask;    /* real name, in mask format */
2848         tp2 = maskp;    /* mask, in mask format */
2849         for(i=0; i<11; i++) {
2850                 tc1 = *tp1++;   /* char from real name */
2851                 tc2 = *tp2++;   /* char from mask */
2852                 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2853                 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2854                 if (tc1 == tc2) 
2855                         continue;
2856                 if (tc2 == '?' && tc1 != ' ') 
2857                         continue;
2858                 if (tc2 == '>') 
2859                         continue;
2860                 return 0;
2861         }
2862
2863         /* we got a match */
2864         return 1;
2865 }
2866
2867 char *smb_FindMask(char *pathp)
2868 {
2869         char *tp;
2870         
2871         tp = strrchr(pathp, '\\');      /* find last slash */
2872
2873         if (tp) 
2874                 return tp+1;    /* skip the slash */
2875         else 
2876                 return pathp;   /* no slash, return the entire path */
2877 }
2878
2879 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2880 {
2881         unsigned char *pathp;
2882         unsigned char *tp;
2883         unsigned char mask[11];
2884         unsigned char *statBlockp;
2885         unsigned char initStatBlock[21];
2886         int statLen;
2887         
2888         osi_Log0(smb_logp, "SMB receive search volume");
2889
2890         /* pull pathname and stat block out of request */
2891         tp = smb_GetSMBData(inp, NULL);
2892         pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2893         osi_assert(pathp != NULL);
2894         statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2895         osi_assert(statBlockp != NULL);
2896         if (statLen == 0) {
2897                 statBlockp = initStatBlock;
2898                 statBlockp[0] = 8;
2899         }
2900         
2901         /* for returning to caller */
2902         smb_Get8Dot3MaskFromPath(mask, pathp);
2903         
2904         smb_SetSMBParm(outp, 0, 1);             /* we're returning one entry */
2905         tp = smb_GetSMBData(outp, NULL);
2906         *tp++ = 5;
2907         *tp++ = 43;     /* bytes in a dir entry */
2908         *tp++ = 0;      /* high byte in counter */
2909
2910         /* now marshall the dir entry, starting with the search status */
2911         *tp++ = statBlockp[0];          /* Reserved */
2912         memcpy(tp, mask, 11); tp += 11; /* FileName */
2913
2914         /* now pass back server use info, with 1st byte non-zero */
2915         *tp++ = 1;
2916         memset(tp, 0, 4); tp += 4;      /* reserved for server use */
2917
2918         memcpy(tp, statBlockp+17, 4); tp += 4;  /* reserved for consumer */
2919
2920         *tp++ = 0x8;            /* attribute: volume */
2921
2922         /* copy out time */
2923         *tp++ = 0;
2924         *tp++ = 0;
2925
2926         /* copy out date */
2927         *tp++ = 18;
2928         *tp++ = 178;
2929
2930         /* 4 byte file size */
2931         *tp++ = 0;
2932         *tp++ = 0;
2933         *tp++ = 0;
2934         *tp++ = 0;
2935
2936         /* finally, null-terminated 8.3 pathname, which we set to AFS */
2937         memset(tp, ' ', 13);
2938         strcpy(tp, "AFS");
2939
2940         /* set the length of the data part of the packet to 43 + 3, for the dir
2941          * entry plus the 5 and the length fields.
2942          */
2943         smb_SetSMBDataLength(outp, 46);
2944         return 0;
2945 }
2946
2947 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2948         cm_user_t *userp, cm_req_t *reqp)
2949 {
2950         long code = 0;
2951         cm_scache_t *scp;
2952         char *dptr;
2953         long dosTime;
2954         u_short shortTemp;
2955         char attr;
2956         smb_dirListPatch_t *patchp;
2957         smb_dirListPatch_t *npatchp;
2958
2959         for(patchp = *dirPatchespp; patchp; patchp =
2960                  (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2961                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2962                 if (code) continue;
2963                 lock_ObtainMutex(&scp->mx);
2964                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2965                                                   CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2966                 if (code) {     
2967                         lock_ReleaseMutex(&scp->mx);
2968                         cm_ReleaseSCache(scp);
2969                         continue;
2970                 }
2971                 dptr = patchp->dptr;
2972
2973                 attr = smb_Attributes(scp);
2974         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
2975         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2976             attr |= SMB_ATTR_HIDDEN;
2977         *dptr++ = attr;
2978
2979                 /* get dos time */
2980                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2981                 
2982                 /* copy out time */
2983                 shortTemp = dosTime & 0xffff;
2984                 *((u_short *)dptr) = shortTemp;
2985                 dptr += 2;
2986
2987                 /* and copy out date */
2988                 shortTemp = (dosTime>>16) & 0xffff;
2989                 *((u_short *)dptr) = shortTemp;
2990                 dptr += 2;
2991                 
2992                 /* copy out file length */
2993                 *((u_long *)dptr) = scp->length.LowPart;
2994                 dptr += 4;
2995                 lock_ReleaseMutex(&scp->mx);
2996                 cm_ReleaseSCache(scp);
2997         }
2998         
2999         /* now free the patches */
3000         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3001                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3002                 free(patchp);
3003         }       
3004         
3005         /* and mark the list as empty */
3006         *dirPatchespp = NULL;
3007
3008         return code;
3009 }
3010
3011 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3012 {
3013         int attribute;
3014         long nextCookie;
3015         char *tp;
3016         long code = 0;
3017         char *pathp;
3018         cm_dirEntry_t *dep;
3019         int maxCount;
3020         smb_dirListPatch_t *dirListPatchesp;
3021         smb_dirListPatch_t *curPatchp;
3022         int dataLength;
3023         cm_buf_t *bufferp;
3024         long temp;
3025         osi_hyper_t dirLength;
3026         osi_hyper_t bufferOffset;
3027         osi_hyper_t curOffset;
3028         osi_hyper_t thyper;
3029         unsigned char *inCookiep;
3030         smb_dirSearch_t *dsp;
3031         cm_scache_t *scp;
3032         long entryInDir;
3033         long entryInBuffer;
3034         unsigned long clientCookie;
3035         cm_pageHeader_t *pageHeaderp;
3036         cm_user_t *userp = NULL;
3037         int slotInPage;
3038         char shortName[13];
3039         char *actualName;
3040         char *shortNameEnd;
3041         char mask[11];
3042         int returnedNames;
3043         long nextEntryCookie;
3044         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
3045         char resByte;                   /* reserved byte from the cookie */
3046         char *op;                       /* output data ptr */
3047         char *origOp;                   /* original value of op */
3048         cm_space_t *spacep;             /* for pathname buffer */
3049         int starPattern;
3050         int rootPath = 0;
3051         int caseFold;
3052         char *tidPathp;
3053         cm_req_t req;
3054         cm_fid_t fid;
3055         int fileType;
3056
3057         cm_InitReq(&req);
3058
3059         maxCount = smb_GetSMBParm(inp, 0);
3060
3061         dirListPatchesp = NULL;
3062         
3063         caseFold = CM_FLAG_CASEFOLD;
3064
3065         tp = smb_GetSMBData(inp, NULL);
3066         pathp = smb_ParseASCIIBlock(tp, &tp);
3067         inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3068
3069         /* bail out if request looks bad */
3070         if (!tp || !pathp) {
3071                 return CM_ERROR_BADSMB;
3072         }
3073
3074         /* We can handle long names */
3075         if (vcp->flags & SMB_VCFLAG_USENT)
3076                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
3077
3078         /* make sure we got a whole search status */
3079         if (dataLength < 21) {
3080                 nextCookie = 0;         /* start at the beginning of the dir */
3081                 resByte = 0;
3082                 clientCookie = 0;
3083                 attribute = smb_GetSMBParm(inp, 1);
3084
3085                 /* handle volume info in another function */
3086                 if (attribute & 0x8)
3087                         return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3088
3089                 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3090                                  maxCount, osi_LogSaveString(smb_logp, pathp));
3091
3092                 if (*pathp == 0) {      /* null pathp, treat as root dir */
3093                         if (!(attribute & SMB_ATTR_DIRECTORY))  /* exclude dirs */
3094                                 return CM_ERROR_NOFILES;
3095                         rootPath = 1;
3096                 }
3097
3098                 dsp = smb_NewDirSearch(0);
3099                 dsp->attribute = attribute;
3100                 smb_Get8Dot3MaskFromPath(mask, pathp);
3101                 memcpy(dsp->mask, mask, 11);
3102
3103                 /* track if this is likely to match a lot of entries */
3104                 if (smb_IsStarMask(mask)) starPattern = 1;
3105                 else starPattern = 0;
3106         }       
3107         else {
3108                 /* pull the next cookie value out of the search status block */
3109                 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3110                         + (inCookiep[16]<<24);
3111                 dsp = smb_FindDirSearch(inCookiep[12]);
3112                 if (!dsp) {
3113                         /* can't find dir search status; fatal error */
3114                         return CM_ERROR_BADFD;
3115                 }
3116                 attribute = dsp->attribute;
3117                 resByte = inCookiep[0];
3118
3119                 /* copy out client cookie, in host byte order.  Don't bother
3120                  * interpreting it, since we're just passing it through, anyway.
3121                  */
3122                 memcpy(&clientCookie, &inCookiep[17], 4);
3123
3124                 memcpy(mask, dsp->mask, 11);
3125
3126                 /* assume we're doing a star match if it has continued for more
3127                  * than one call.
3128                  */
3129                 starPattern = 1;
3130         }
3131
3132         osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3133                          nextCookie, dsp->cookie, attribute);
3134
3135         userp = smb_GetUser(vcp, inp);
3136
3137         /* try to get the vnode for the path name next */
3138         lock_ObtainMutex(&dsp->mx);
3139         if (dsp->scp) {
3140                 scp = dsp->scp;
3141                 cm_HoldSCache(scp);
3142                 code = 0;
3143         }
3144         else {
3145                 spacep = inp->spacep;
3146                 smb_StripLastComponent(spacep->data, NULL, pathp);
3147                 lock_ReleaseMutex(&dsp->mx);
3148                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3149                 code = cm_NameI(cm_rootSCachep, spacep->data,
3150                                                 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3151                 lock_ObtainMutex(&dsp->mx);
3152                 if (code == 0) {
3153                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3154                         dsp->scp = scp;
3155                         /* we need one hold for the entry we just stored into,
3156                          * and one for our own processing.  When we're done with this
3157                          * function, we'll drop the one for our own processing.
3158                          * We held it once from the namei call, and so we do another hold
3159                          * now.
3160                          */
3161                         cm_HoldSCache(scp);
3162                         lock_ObtainMutex(&scp->mx);
3163                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3164                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3165                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3166                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3167                         }
3168                         lock_ReleaseMutex(&scp->mx);
3169                 }
3170         }
3171         lock_ReleaseMutex(&dsp->mx);
3172         if (code) {
3173                 cm_ReleaseUser(userp);
3174                 smb_DeleteDirSearch(dsp);
3175                 smb_ReleaseDirSearch(dsp);
3176                 return code;
3177         }
3178
3179         /* reserves space for parameter; we'll adjust it again later to the
3180          * real count of the # of entries we returned once we've actually
3181          * assembled the directory listing.
3182          */
3183         smb_SetSMBParm(outp, 0, 0);
3184         
3185         /* get the directory size */
3186         lock_ObtainMutex(&scp->mx);
3187         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3188                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3189         if (code) {
3190                 lock_ReleaseMutex(&scp->mx);
3191                 cm_ReleaseSCache(scp);
3192                 cm_ReleaseUser(userp);
3193                 smb_DeleteDirSearch(dsp);
3194                 smb_ReleaseDirSearch(dsp);
3195                 return code;
3196         }
3197         
3198         dirLength = scp->length;
3199         bufferp = NULL;
3200         bufferOffset.LowPart = bufferOffset.HighPart = 0;
3201         curOffset.HighPart = 0;
3202         curOffset.LowPart = nextCookie;
3203         origOp = op = smb_GetSMBData(outp, NULL);
3204         /* and write out the basic header */
3205         *op++ = 5;              /* variable block */
3206         op += 2;                /* skip vbl block length; we'll fill it in later */
3207         code = 0;
3208         returnedNames = 0;
3209         while (1) {
3210                 /* make sure that curOffset.LowPart doesn't point to the first
3211                  * 32 bytes in the 2nd through last dir page, and that it doesn't
3212                  * point at the first 13 32-byte chunks in the first dir page,
3213                  * since those are dir and page headers, and don't contain useful
3214                  * information.
3215                  */
3216                 temp = curOffset.LowPart & (2048-1);
3217                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3218                         /* we're in the first page */
3219                         if (temp < 13*32) temp = 13*32;
3220                 }
3221                 else {
3222                         /* we're in a later dir page */
3223                         if (temp < 32) temp = 32;
3224                 }
3225                 
3226                 /* make sure the low order 5 bits are zero */
3227                 temp &= ~(32-1);
3228
3229                 /* now put temp bits back ito curOffset.LowPart */
3230                 curOffset.LowPart &= ~(2048-1);
3231                 curOffset.LowPart |= temp;
3232
3233                 /* check if we've returned all the names that will fit in the
3234                  * response packet.
3235                  */
3236                 if (returnedNames >= maxCount) 
3237                         break;
3238                 
3239                 /* check if we've passed the dir's EOF */
3240                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3241
3242                 /* see if we can use the bufferp we have now; compute in which page
3243                  * the current offset would be, and check whether that's the offset
3244                  * of the buffer we have.  If not, get the buffer.
3245                  */
3246                 thyper.HighPart = curOffset.HighPart;
3247                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3248                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3249                         /* wrong buffer */
3250                         if (bufferp) {
3251                                 buf_Release(bufferp);
3252                                 bufferp = NULL;
3253                         }       
3254                         lock_ReleaseMutex(&scp->mx);
3255                         lock_ObtainRead(&scp->bufCreateLock);
3256                         code = buf_Get(scp, &thyper, &bufferp);
3257                         lock_ReleaseRead(&scp->bufCreateLock);
3258
3259                         /* now, if we're doing a star match, do bulk fetching of all of 
3260                          * the status info for files in the dir.
3261                          */
3262                         if (starPattern) {
3263                                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3264                                                                                 &req);
3265                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3266                                     && LargeIntegerGreaterThanOrEqualTo(thyper, 
3267                                                                         scp->bulkStatProgress)) {
3268                                         /* Don't bulk stat if risking timeout */
3269                                         int now = GetCurrentTime();
3270                                         if (now - req.startTime > 5000) {
3271                                                 scp->bulkStatProgress = thyper;
3272                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3273                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3274                                         } else
3275                                                 cm_TryBulkStat(scp, &thyper, userp, &req);
3276                                 }
3277                         }
3278
3279                         lock_ObtainMutex(&scp->mx);
3280                         if (code) 
3281                                 break;
3282                         bufferOffset = thyper;
3283
3284                         /* now get the data in the cache */
3285                         while (1) {
3286                                 code = cm_SyncOp(scp, bufferp, userp, &req,
3287                                                                   PRSFS_LOOKUP,
3288                                                                   CM_SCACHESYNC_NEEDCALLBACK
3289                                                                   | CM_SCACHESYNC_READ);
3290                                 if (code) break;
3291                                 
3292                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3293
3294                                 /* otherwise, load the buffer and try again */
3295                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3296                                                                         &req);
3297                                 if (code) break;
3298                         }
3299                         if (code) {
3300                                 buf_Release(bufferp);
3301                                 bufferp = NULL;
3302                                 break;
3303                         }
3304                 }       /* if (wrong buffer) ... */
3305
3306                 /* now we have the buffer containing the entry we're interested in; copy
3307                  * it out if it represents a non-deleted entry.
3308                  */
3309                 entryInDir = curOffset.LowPart & (2048-1);
3310                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3311
3312                 /* page header will help tell us which entries are free.  Page header
3313                  * can change more often than once per buffer, since AFS 3 dir page size
3314                  * may be less than (but not more than a buffer package buffer.
3315                  */
3316                 temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
3317                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
3318                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3319
3320                 /* now determine which entry we're looking at in the page.  If it is
3321                  * free (there's a free bitmap at the start of the dir), we should
3322                  * skip these 32 bytes.
3323                  */
3324                 slotInPage = (entryInDir & 0x7e0) >> 5;
3325                 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3326                         /* this entry is free */
3327                         numDirChunks = 1;               /* only skip this guy */
3328                         goto nextEntry;
3329                 }
3330
3331                 tp = bufferp->datap + entryInBuffer;
3332                 dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3333
3334                 /* while we're here, compute the next entry's location, too,
3335                  * since we'll need it when writing out the cookie into the dir
3336                  * listing stream.
3337                  *
3338                  * XXXX Probably should do more sanity checking.
3339                  */
3340                 numDirChunks = cm_NameEntries(dep->name, NULL);
3341                 
3342                 /* compute the offset of the cookie representing the next entry */
3343                 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3344
3345                 /* Compute 8.3 name if necessary */
3346                 actualName = dep->name;
3347                 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3348                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3349                         actualName = shortName;
3350                 }
3351
3352                 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3353                         /* this is one of the entries to use: it is not deleted
3354                          * and it matches the star pattern we're looking for.
3355                          */
3356
3357                         /* Eliminate entries that don't match requested
3358                            attributes */
3359
3360                         /* no hidden files */
3361                         if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3362                                 goto nextEntry;
3363
3364                         if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3365                         {
3366                                 /* We have already done the cm_TryBulkStat above */
3367                                 fid.cell = scp->fid.cell;
3368                                 fid.volume = scp->fid.volume;
3369                                 fid.vnode = ntohl(dep->fid.vnode);
3370                                 fid.unique = ntohl(dep->fid.unique);
3371                                 fileType = cm_FindFileType(&fid);
3372                                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3373                                                   "has filetype %d", dep->name,
3374                                                   fileType);
3375                                 if (fileType == CM_SCACHETYPE_DIRECTORY)
3376                                         goto nextEntry;
3377                         }
3378
3379                         *op++ = resByte;
3380                         memcpy(op, mask, 11); op += 11;
3381                         *op++ = (char) dsp->cookie;     /* they say it must be non-zero */
3382                         *op++ = nextEntryCookie & 0xff;
3383                         *op++ = (nextEntryCookie>>8) & 0xff;
3384                         *op++ = (nextEntryCookie>>16) & 0xff;
3385                         *op++ = (nextEntryCookie>>24) & 0xff;
3386                         memcpy(op, &clientCookie, 4); op += 4;
3387
3388                         /* now we emit the attribute.  This is sort of tricky,
3389                          * since we need to really stat the file to find out
3390                          * what type of entry we've got.  Right now, we're
3391                          * copying out data from a buffer, while holding the
3392                          * scp locked, so it isn't really convenient to stat
3393                          * something now.  We'll put in a place holder now,
3394                          * and make a second pass before returning this to get
3395                          * the real attributes.  So, we just skip the data for
3396                          * now, and adjust it later.  We allocate a patch
3397                          * record to make it easy to find this point later.
3398                          * The replay will happen at a time when it is safe to
3399                          * unlock the directory.
3400                          */
3401                         curPatchp = malloc(sizeof(*curPatchp));
3402                         osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3403                         curPatchp->dptr = op;
3404                         curPatchp->fid.cell = scp->fid.cell;
3405                         curPatchp->fid.volume = scp->fid.volume;
3406                         curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3407                         curPatchp->fid.unique = ntohl(dep->fid.unique);
3408
3409                         /* do hidden attribute here since name won't be around when applying
3410                          * dir list patches
3411                          */
3412
3413                         if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3414                                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3415                         else
3416                                 curPatchp->flags = 0;
3417
3418                         op += 9;        /* skip attr, time, date and size */
3419
3420                         /* zero out name area.  The spec says to pad with
3421                          * spaces, but Samba doesn't, and neither do we.
3422                          */
3423                         memset(op, 0, 13);
3424
3425                         /* finally, we get to copy out the name; we know that
3426                          * it fits in 8.3 or the pattern wouldn't match, but it
3427                          * never hurts to be sure.
3428                          */
3429                         strncpy(op, actualName, 13);
3430
3431                         /* Uppercase if requested by client */
3432                         if ((((smb_t *)inp)->flg2 & 1) == 0)
3433                                 _strupr(op);
3434
3435                         op += 13;
3436
3437                         /* now, adjust the # of entries copied */
3438                         returnedNames++;
3439                 }       /* if we're including this name */
3440                 
3441           nextEntry:
3442                 /* and adjust curOffset to be where the new cookie is */
3443                 thyper.HighPart = 0;
3444                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3445                 curOffset = LargeIntegerAdd(thyper, curOffset);
3446         }               /* while copying data for dir listing */
3447
3448         /* release the mutex */
3449         lock_ReleaseMutex(&scp->mx);
3450         if (bufferp) buf_Release(bufferp);
3451
3452         /* apply and free last set of patches; if not doing a star match, this
3453          * will be empty, but better safe (and freeing everything) than sorry.
3454          */
3455         smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3456
3457         /* special return code for unsuccessful search */
3458         if (code == 0 && dataLength < 21 && returnedNames == 0)
3459                 code = CM_ERROR_NOFILES;
3460
3461         osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3462                  returnedNames, code);
3463
3464         if (code != 0) {
3465                 smb_DeleteDirSearch(dsp);
3466                 smb_ReleaseDirSearch(dsp);
3467                 cm_ReleaseSCache(scp);
3468                 cm_ReleaseUser(userp);
3469                 return code;
3470         }
3471
3472         /* finalize the output buffer */
3473         smb_SetSMBParm(outp, 0, returnedNames);
3474         temp = (long) (op - origOp);
3475         smb_SetSMBDataLength(outp, temp);
3476
3477         /* the data area is a variable block, which has a 5 (already there)
3478          * followed by the length of the # of data bytes.  We now know this to
3479          * be "temp," although that includes the 3 bytes of vbl block header.
3480          * Deduct for them and fill in the length field.
3481          */
3482         temp -= 3;              /* deduct vbl block info */
3483         osi_assert(temp == (43 * returnedNames));
3484         origOp[1] = temp & 0xff;
3485         origOp[2] = (temp>>8) & 0xff;
3486         if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3487         smb_ReleaseDirSearch(dsp);
3488         cm_ReleaseSCache(scp);
3489         cm_ReleaseUser(userp);
3490         return code;
3491 }       
3492
3493 /* verify that this is a valid path to a directory.  I don't know why they
3494  * don't use the get file attributes call.
3495  */
3496 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3497 {
3498         char *pathp;
3499         long code = 0;
3500         cm_scache_t *rootScp;
3501         cm_scache_t *newScp;
3502         cm_user_t *userp;
3503         unsigned int attrs;
3504         int caseFold;
3505         char *tidPathp;
3506         cm_req_t req;
3507
3508         cm_InitReq(&req);
3509
3510         pathp = smb_GetSMBData(inp, NULL);
3511         pathp = smb_ParseASCIIBlock(pathp, NULL);
3512         osi_Log1(smb_logp, "SMB receive check path %s",
3513                           osi_LogSaveString(smb_logp, pathp));
3514
3515         if (!pathp) {
3516                 return CM_ERROR_BADFD;
3517         }
3518         
3519         rootScp = cm_rootSCachep;
3520         
3521         userp = smb_GetUser(vcp, inp);
3522
3523         caseFold = CM_FLAG_CASEFOLD;
3524
3525         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3526         code = cm_NameI(rootScp, pathp,
3527                                          caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3528                                          userp, tidPathp, &req, &newScp);
3529
3530         if (code) {
3531                 cm_ReleaseUser(userp);
3532                 return code;
3533         }
3534         
3535         /* now lock the vnode with a callback; returns with newScp locked */
3536         lock_ObtainMutex(&newScp->mx);
3537         code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3538                                           CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3539         if (code && code != CM_ERROR_NOACCESS) {
3540                 lock_ReleaseMutex(&newScp->mx);
3541                 cm_ReleaseSCache(newScp);
3542                 cm_ReleaseUser(userp);
3543                 return code;
3544         }
3545
3546         attrs = smb_Attributes(newScp);
3547
3548         if (!(attrs & 0x10))
3549                 code = CM_ERROR_NOTDIR;
3550
3551         lock_ReleaseMutex(&newScp->mx);
3552
3553         cm_ReleaseSCache(newScp);
3554         cm_ReleaseUser(userp);
3555         return code;
3556 }       
3557
3558 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3559 {
3560         char *pathp;
3561         long code = 0;
3562         cm_scache_t *rootScp;
3563         unsigned short attribute;
3564         cm_attr_t attr;
3565         cm_scache_t *newScp;
3566         long dosTime;
3567         cm_user_t *userp;
3568         int caseFold;
3569         char *tidPathp;
3570         cm_req_t req;
3571
3572         cm_InitReq(&req);
3573
3574         /* decode basic attributes we're passed */
3575         attribute = smb_GetSMBParm(inp, 0);
3576         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3577
3578         pathp = smb_GetSMBData(inp, NULL);
3579         pathp = smb_ParseASCIIBlock(pathp, NULL);
3580         
3581         if (!pathp) {
3582                 return CM_ERROR_BADSMB;
3583         }
3584         
3585         osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3586                          dosTime, attribute);
3587
3588         rootScp = cm_rootSCachep;
3589         
3590         userp = smb_GetUser(vcp, inp);
3591
3592         caseFold = CM_FLAG_CASEFOLD;
3593
3594         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3595         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3596                                         tidPathp, &req, &newScp);
3597
3598         if (code) {
3599                 cm_ReleaseUser(userp);
3600                 return code;
3601         }
3602         
3603         /* now lock the vnode with a callback; returns with newScp locked; we
3604          * need the current status to determine what the new status is, in some
3605          * cases.
3606          */
3607         lock_ObtainMutex(&newScp->mx);
3608         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3609                                          CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3610         if (code) {
3611                 lock_ReleaseMutex(&newScp->mx);
3612                 cm_ReleaseSCache(newScp);
3613                 cm_ReleaseUser(userp);
3614                 return code;
3615         }
3616
3617         /* Check for RO volume */
3618         if (newScp->flags & CM_SCACHEFLAG_RO) {
3619                 lock_ReleaseMutex(&newScp->mx);
3620                 cm_ReleaseSCache(newScp);
3621                 cm_ReleaseUser(userp);
3622                 return CM_ERROR_READONLY;
3623         }
3624
3625         /* prepare for setattr call */
3626         attr.mask = 0;
3627         if (dosTime != 0) {
3628                 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3629                 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3630         }
3631         if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3632                 /* we're told to make a writable file read-only */
3633                 attr.unixModeBits = newScp->unixModeBits & ~0222;
3634                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3635         }
3636         else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3637                 /* we're told to make a read-only file writable */
3638                 attr.unixModeBits = newScp->unixModeBits | 0222;
3639                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3640         }
3641         lock_ReleaseMutex(&newScp->mx);
3642
3643         /* now call setattr */
3644         if (attr.mask)
3645                 code = cm_SetAttr(newScp, &attr, userp, &req);
3646         else
3647                 code = 0;
3648         
3649         cm_ReleaseSCache(newScp);
3650         cm_ReleaseUser(userp);
3651
3652         return code;
3653 }
3654
3655 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3656 {
3657         char *pathp;
3658         long code = 0;
3659         cm_scache_t *rootScp;
3660         cm_scache_t *newScp, *dscp;
3661         long dosTime;
3662         int attrs;
3663         cm_user_t *userp;
3664         int caseFold;
3665         char *tidPathp;
3666         cm_space_t *spacep;
3667         char *lastComp;
3668         cm_req_t req;
3669
3670         cm_InitReq(&req);
3671
3672         pathp = smb_GetSMBData(inp, NULL);
3673         pathp = smb_ParseASCIIBlock(pathp, NULL);
3674         
3675         if (!pathp) {
3676                 return CM_ERROR_BADSMB;
3677         }
3678         
3679         if (*pathp == 0)                /* null path */
3680                 pathp = "\\";
3681
3682         osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3683                          osi_LogSaveString(smb_logp, pathp));
3684
3685         rootScp = cm_rootSCachep;
3686         
3687         userp = smb_GetUser(vcp, inp);
3688
3689         /* we shouldn't need this for V3 requests, but we seem to */
3690         caseFold = CM_FLAG_CASEFOLD;
3691
3692         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3693
3694         /*
3695          * XXX Strange hack XXX
3696          *
3697          * As of Patch 5 (16 July 97), we are having the following problem:
3698          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3699          * requests to look up "desktop.ini" in all the subdirectories.
3700          * This can cause zillions of timeouts looking up non-existent cells
3701          * and volumes, especially in the top-level directory.
3702          *
3703          * We have not found any way to avoid this or work around it except
3704          * to explicitly ignore the requests for mount points that haven't
3705          * yet been evaluated and for directories that haven't yet been
3706          * fetched.
3707          *
3708          * We should modify this hack to provide a fake desktop.ini file
3709          * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3710          */
3711         spacep = inp->spacep;
3712         smb_StripLastComponent(spacep->data, &lastComp, pathp);
3713         if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3714                 code = cm_NameI(rootScp, spacep->data,
3715                                                 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3716                                                 userp, tidPathp, &req, &dscp);
3717                 if (code == 0) {
3718                         if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3719                             && !dscp->mountRootFidp)
3720                                 code = CM_ERROR_NOSUCHFILE;
3721                         else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3722                                 cm_buf_t *bp = buf_Find(dscp, &hzero);
3723                                 if (bp)
3724                                         buf_Release(bp);
3725                                 else
3726                                         code = CM_ERROR_NOSUCHFILE;
3727                         }
3728                         cm_ReleaseSCache(dscp);
3729                         if (code) {
3730                                 cm_ReleaseUser(userp);
3731                                 return code;
3732                         }
3733                 }
3734         }
3735
3736         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3737                                         tidPathp, &req, &newScp);
3738
3739         if (code) {
3740                 cm_ReleaseUser(userp);
3741                 return code;
3742         }
3743         
3744         /* now lock the vnode with a callback; returns with newScp locked */
3745         lock_ObtainMutex(&newScp->mx);
3746         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3747                                          CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3748         if (code) {
3749                 lock_ReleaseMutex(&newScp->mx);
3750                 cm_ReleaseSCache(newScp);
3751                 cm_ReleaseUser(userp);
3752                 return code;
3753         }
3754
3755 #ifdef undef
3756     /* use smb_Attributes instead.   Also the fact that a file is 
3757          * in a readonly volume doesn't mean it shojuld be marked as RO 
3758          */
3759         if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3760                 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3761                 attrs = SMB_ATTR_DIRECTORY;
3762         else
3763                 attrs = 0;
3764         if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
3765                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
3766 #else
3767     attrs = smb_Attributes(newScp);
3768 #endif
3769
3770         smb_SetSMBParm(outp, 0, attrs);
3771         
3772         smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
3773         smb_SetSMBParm(outp, 1, dosTime & 0xffff);
3774         smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
3775         smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
3776         smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
3777         smb_SetSMBParm(outp, 5, 0);
3778         smb_SetSMBParm(outp, 6, 0);
3779         smb_SetSMBParm(outp, 7, 0);
3780         smb_SetSMBParm(outp, 8, 0);
3781         smb_SetSMBParm(outp, 9, 0);
3782         smb_SetSMBDataLength(outp, 0);
3783         lock_ReleaseMutex(&newScp->mx);
3784
3785         cm_ReleaseSCache(newScp);
3786         cm_ReleaseUser(userp);
3787         
3788         return 0;
3789 }       
3790
3791 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3792 {
3793         smb_tid_t *tidp;
3794         
3795         osi_Log0(smb_logp, "SMB receive tree disconnect");
3796
3797         /* find the tree and free it */
3798         tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
3799         if (tidp) {
3800                 lock_ObtainMutex(&tidp->mx);
3801                 tidp->flags |= SMB_TIDFLAG_DELETE;
3802                 lock_ReleaseMutex(&tidp->mx);
3803                 smb_ReleaseTID(tidp);
3804         }
3805
3806         return 0;
3807 }
3808
3809 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3810 {
3811         smb_fid_t *fidp;
3812     char *pathp;
3813         char *lastNamep;
3814     int share;
3815     int attribute;
3816         long code = 0;
3817     cm_user_t *userp;
3818     cm_scache_t *scp;
3819     long dosTime;
3820     int caseFold;
3821         cm_space_t *spacep;
3822         char *tidPathp;
3823         cm_req_t req;
3824
3825         cm_InitReq(&req);
3826
3827     pathp = smb_GetSMBData(inp, NULL);
3828     pathp = smb_ParseASCIIBlock(pathp, NULL);
3829         
3830     osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
3831
3832 #ifdef DEBUG_VERBOSE
3833     {
3834         char *hexpath;
3835
3836         hexpath = osi_HexifyString( pathp );
3837         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
3838         free(hexpath);
3839     }
3840 #endif
3841
3842         share = smb_GetSMBParm(inp, 0);
3843     attribute = smb_GetSMBParm(inp, 1);
3844
3845         spacep = inp->spacep;
3846         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3847         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3848                 /* special case magic file name for receiving IOCTL requests
3849          * (since IOCTL calls themselves aren't getting through).
3850          */
3851         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3852                 smb_SetupIoctlFid(fidp, spacep);
3853                 smb_SetSMBParm(outp, 0, fidp->fid);
3854         smb_SetSMBParm(outp, 1, 0);     /* attrs */
3855         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
3856         smb_SetSMBParm(outp, 3, 0);
3857         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
3858         smb_SetSMBParm(outp, 5, 0x7fff);
3859                 /* pass the open mode back */
3860         smb_SetSMBParm(outp, 6, (share & 0xf));
3861         smb_SetSMBDataLength(outp, 0);
3862         smb_ReleaseFID(fidp);
3863         return 0;
3864     }
3865
3866         userp = smb_GetUser(vcp, inp);
3867
3868         caseFold = CM_FLAG_CASEFOLD;
3869
3870         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3871     code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3872                     tidPathp, &req, &scp);
3873         
3874     if (code) {
3875         cm_ReleaseUser(userp);
3876                 return code;
3877         }
3878         
3879     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
3880         if (code) {
3881                 cm_ReleaseSCache(scp);
3882                 cm_ReleaseUser(userp);
3883                 return code;
3884         }
3885
3886         /* don't need callback to check file type, since file types never
3887          * change, and namei and cm_Lookup all stat the object at least once on
3888          * a successful return.
3889      */
3890     if (scp->fileType != CM_SCACHETYPE_FILE) {
3891                 cm_ReleaseSCache(scp);
3892         cm_ReleaseUser(userp);
3893         return CM_ERROR_ISDIR;
3894     }
3895
3896     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3897     osi_assert(fidp);
3898
3899         /* save a pointer to the vnode */
3900     fidp->scp = scp;
3901
3902     if ((share & 0xf) == 0)
3903         fidp->flags |= SMB_FID_OPENREAD;
3904         else if ((share & 0xf) == 1)
3905         fidp->flags |= SMB_FID_OPENWRITE;
3906         else 
3907         fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
3908
3909         lock_ObtainMutex(&scp->mx);
3910         smb_SetSMBParm(outp, 0, fidp->fid);
3911     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
3912         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3913     smb_SetSMBParm(outp, 2, dosTime & 0xffff);
3914     smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
3915     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
3916     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
3917         /* pass the open mode back; XXXX add access checks */
3918     smb_SetSMBParm(outp, 6, (share & 0xf));
3919     smb_SetSMBDataLength(outp, 0);
3920         lock_ReleaseMutex(&scp->mx);
3921         
3922         /* notify open */
3923     cm_Open(scp, 0, userp);
3924
3925         /* send and free packet */
3926     smb_ReleaseFID(fidp);
3927     cm_ReleaseUser(userp);
3928     /* don't release scp, since we've squirreled away the pointer in the fid struct */
3929     return 0;
3930 }
3931
3932 typedef struct smb_unlinkRock {
3933         cm_scache_t *dscp;
3934         cm_user_t *userp;
3935         cm_req_t *reqp;
3936         smb_vc_t *vcp;
3937         char *maskp;            /* pointer to the star pattern */
3938         int flags;
3939         int any;
3940 } smb_unlinkRock_t;
3941
3942 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3943 {
3944         long code = 0;
3945         smb_unlinkRock_t *rockp;
3946         int caseFold;
3947         int match;
3948         char shortName[13];
3949         char *matchName;
3950         
3951         rockp = vrockp;
3952
3953     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
3954     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
3955         caseFold |= CM_FLAG_8DOT3;
3956
3957         matchName = dep->name;
3958         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3959         if (!match
3960             && (rockp->flags & SMB_MASKFLAG_TILDE)
3961             && !cm_Is8Dot3(dep->name)) {
3962                 cm_Gen8Dot3Name(dep, shortName, NULL);
3963                 matchName = shortName;
3964         /* 8.3 matches are always case insensitive */
3965         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
3966         }
3967         if (match) {
3968                 osi_Log1(smb_logp, "Unlinking %s",
3969                                  osi_LogSaveString(smb_logp, matchName));
3970                 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
3971                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3972                         smb_NotifyChange(FILE_ACTION_REMOVED,
3973                                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3974                                                          dscp, dep->name, NULL, TRUE);
3975                 if (code == 0) {
3976                         rockp->any = 1;
3977             /* If we made a case sensitive exact match, we might as well quit now. */
3978             if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
3979                 code = CM_ERROR_STOPNOW;
3980         }
3981         }
3982         else code = 0;
3983
3984         return code;
3985 }
3986
3987 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3988 {
3989         int attribute;
3990         long code = 0;
3991         char *pathp;
3992         char *tp;
3993         cm_space_t *spacep;
3994         cm_scache_t *dscp;
3995         char *lastNamep;
3996         smb_unlinkRock_t rock;
3997         cm_user_t *userp;
3998         osi_hyper_t thyper;
3999         int caseFold;
4000         char *tidPathp;
4001         cm_req_t req;
4002
4003         cm_InitReq(&req);
4004
4005         attribute = smb_GetSMBParm(inp, 0);
4006         
4007         tp = smb_GetSMBData(inp, NULL);
4008         pathp = smb_ParseASCIIBlock(tp, &tp);
4009
4010         osi_Log1(smb_logp, "SMB receive unlink %s",
4011                          osi_LogSaveString(smb_logp, pathp));
4012
4013         spacep = inp->spacep;
4014         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4015
4016         userp = smb_GetUser(vcp, inp);
4017
4018         caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4019
4020         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4021         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4022                          &n