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