afsd-improvements-20040403
[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 /* MessageBox or something like it */
143 int (WINAPI *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
144 #endif /* DJGPP */
145
146 /* GMT time info:
147  * Time in Unix format of midnight, 1/1/1970 local time.
148  * When added to dosUTime, gives Unix (AFS) time.
149  */
150 long smb_localZero;
151
152 /* Time difference for converting to kludge-GMT */
153 int smb_NowTZ;
154
155 char *smb_localNamep = NULL;
156
157 smb_vc_t *smb_allVCsp;
158
159 smb_username_t *usernamesp = NULL;
160
161 smb_waitingLock_t *smb_allWaitingLocks;
162
163 /* forward decl */
164 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
165                                                 NCB *ncbp, raw_write_cont_t *rwcp);
166 void smb_NetbiosInit();
167 #ifdef DJGPP
168 #ifndef AFS_WIN95_ENV
169 DWORD smb_ServerExceptionFilter(void);
170 #endif
171
172 extern char cm_HostName[];
173 extern char cm_confDir[];
174 #endif
175
176 #ifdef DJGPP
177 #define LPTSTR char *
178 #define GetComputerName(str, sizep) \
179        strcpy((str), cm_HostName); \
180        *(sizep) = strlen(cm_HostName)
181 #endif /* DJGPP */
182
183 extern char AFSConfigKeyName[];
184
185 /*
186  * Demo expiration
187  *
188  * To build an expiring version, comment out the definition of NOEXPIRE,
189  * and set the definition of EXPIREDATE to the desired value.
190  */
191 #define NOEXPIRE 1
192 #define EXPIREDATE 834000000            /* Wed Jun 5 1996 */
193
194
195 char * myCrt_Dispatch(int i)
196 {
197         switch (i)
198         {
199         default:
200                 return "unknown SMB op";
201         case 0x00:
202                 return "(00)ReceiveCoreMakeDir";
203         case 0x01:
204                 return "(01)ReceiveCoreRemoveDir";
205         case 0x02:
206                 return "(02)ReceiveCoreOpen";
207         case 0x03:
208                 return "(03)ReceiveCoreCreate";
209         case 0x04:
210                 return "(04)ReceiveCoreClose";
211         case 0x05:
212                 return "(05)ReceiveCoreFlush";
213         case 0x06:
214                 return "(06)ReceiveCoreUnlink";
215         case 0x07:
216                 return "(07)ReceiveCoreRename";
217         case 0x08:
218                 return "(08)ReceiveCoreGetFileAttributes";
219         case 0x09:
220                 return "(09)ReceiveCoreSetFileAttributes";
221         case 0x0a:
222                 return "(0a)ReceiveCoreRead";
223         case 0x0b:
224                 return "(0b)ReceiveCoreWrite";
225         case 0x0c:
226                 return "(0c)ReceiveCoreLockRecord";
227         case 0x0d:
228                 return "(0d)ReceiveCoreUnlockRecord";
229         case 0x0e:
230                 return "(0e)SendCoreBadOp";
231         case 0x0f:
232                 return "(0f)ReceiveCoreCreate";
233         case 0x10:
234                 return "(10)ReceiveCoreCheckPath";
235         case 0x11:
236                 return "(11)SendCoreBadOp";
237         case 0x12:
238                 return "(12)ReceiveCoreSeek";
239         case 0x1a:
240                 return "(1a)ReceiveCoreReadRaw";
241         case 0x1d:
242                 return "(1d)ReceiveCoreWriteRawDummy";
243         case 0x22:
244                 return "(22)ReceiveV3SetAttributes";
245         case 0x23:
246                 return "(23)ReceiveV3GetAttributes";
247         case 0x24:
248                 return "(24)ReceiveV3LockingX";
249         case 0x29:
250                 return "(29)SendCoreBadOp";
251         case 0x2b:
252                 return "(2b)ReceiveCoreEcho";
253         case 0x2d:
254                 return "(2d)ReceiveV3OpenX";
255         case 0x2e:
256                 return "(2e)ReceiveV3ReadX";
257         case 0x32:
258                 return "(32)ReceiveV3Tran2A";
259         case 0x33:
260                 return "(33)ReceiveV3Tran2A";
261         case 0x34:
262                 return "(34)ReceiveV3FindClose";
263         case 0x35:
264                 return "(35)ReceiveV3FindNotifyClose";
265         case 0x70:
266                 return "(70)ReceiveCoreTreeConnect";
267         case 0x71:
268                 return "(71)ReceiveCoreTreeDisconnect";
269         case 0x72:
270                 return "(72)ReceiveNegotiate";
271         case 0x73:
272                 return "(73)ReceiveV3SessionSetupX";
273         case 0x74:
274                 return "(74)ReceiveV3UserLogoffX";
275         case 0x75:
276                 return "(75)ReceiveV3TreeConnectX";
277         case 0x80:
278                 return "(80)ReceiveCoreGetDiskAttributes";
279         case 0x81:
280                 return "(81)ReceiveCoreSearchDir";
281         case 0xA0:
282                 return "(A0)ReceiveNTTransact";
283         case 0xA2:
284                 return "(A2)ReceiveNTCreateX";
285         case 0xA4:
286                 return "(A4)ReceiveNTCancel";
287         case 0xc0:
288                 return "(c0)SendCoreBadOp";
289         case 0xc1:
290                 return "(c1)SendCoreBadOp";
291         case 0xc2:
292                 return "(c2)SendCoreBadOp";
293         case 0xc3:
294                 return "(c3)SendCoreBadOp";
295         }
296 }
297
298 char * myCrt_2Dispatch(int i)
299 {
300         switch (i)
301         {
302         default:
303                 return "unknown SMB op-2";
304         case 0:
305                 return "S(00)CreateFile";
306         case 1:
307                 return "S(01)FindFirst";
308         case 2:
309                 return "S(02)FindNext"; /* FindNext */
310         case 3:
311                 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
312         case 4:
313                 return "S(04)??";
314         case 5:
315                 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
316         case 6:
317                 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
318         case 7:
319                 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
320         case 8:
321                 return "S(08)??_ReceiveTran2SetFileInfo";
322         case 9:
323                 return "S(09)??_ReceiveTran2FSCTL";
324         case 10:
325                 return "S(0a)_ReceiveTran2IOCTL";
326         case 11:
327                 return "S(0b)_ReceiveTran2FindNotifyFirst";
328         case 12:
329                 return "S(0c)_ReceiveTran2FindNotifyNext";
330         case 13:
331                 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
332         }
333 }
334
335 /* scache must be locked */
336 unsigned int smb_Attributes(cm_scache_t *scp)
337 {
338         unsigned int attrs;
339
340         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
341                 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
342                 attrs = SMB_ATTR_DIRECTORY;
343         else
344                 attrs = 0;
345
346         /*
347          * We used to mark a file RO if it was in an RO volume, but that
348          * turns out to be impolitic in NT.  See defect 10007.
349          */
350 #ifdef notdef
351         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
352 #endif
353         if ((scp->unixModeBits & 0222) == 0)
354                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
355
356         return attrs;
357 }
358
359 /* Check if the named file/dir is a dotfile/dotdir */
360 /* String pointed to by lastComp can have leading slashes, but otherwise should have
361    no other patch components */
362 unsigned int smb_IsDotFile(char *lastComp) {
363         char *s;
364         if(lastComp) {
365                 /* skip over slashes */
366         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
367         }
368         else
369                 return 0;
370
371     /* nulls, curdir and parent dir doesn't count */
372         if(!*s) return 0;
373         if(*s == '.') {
374                 if(!*(s + 1)) return 0;
375                 if(*(s+1) == '.' && !*(s + 2)) return 0;
376                 return 1;
377         }
378         return 0;
379 }
380
381 static int ExtractBits(WORD bits, short start, short len)
382 {
383         int end;
384         WORD num;
385
386         end = start + len;
387         
388         num = bits << (16 - end);
389         num = num >> ((16 - end) + start);
390
391         return (int)num;
392 }
393
394 #ifndef DJGPP
395 void ShowUnixTime(char *FuncName, long unixTime)
396 {
397         FILETIME ft;
398         WORD wDate, wTime;
399
400         smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
401                 
402         if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
403                 osi_Log1(afsd_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
404         else {
405                 int day, month, year, sec, min, hour;
406                 char msg[256];
407
408                 day = ExtractBits(wDate, 0, 5);
409                 month = ExtractBits(wDate, 5, 4);
410                 year = ExtractBits(wDate, 9, 7) + 1980;
411
412                 sec = ExtractBits(wTime, 0, 5);
413                 min = ExtractBits(wTime, 5, 6);
414                 hour = ExtractBits(wTime, 11, 5);
415
416                 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
417                 osi_Log1(afsd_logp, "%s", osi_LogSaveString(afsd_logp, msg));
418         }
419 }
420 #endif /* DJGPP */
421
422 #ifndef DJGPP
423 /* Determine if we are observing daylight savings time */
424 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
425 {
426         TIME_ZONE_INFORMATION timeZoneInformation;
427         SYSTEMTIME utc, local, localDST;
428
429         /* Get the time zone info. NT uses this to calc if we are in DST. */
430         GetTimeZoneInformation(&timeZoneInformation);
431  
432         /* Return the daylight bias */
433         *pDstBias = timeZoneInformation.DaylightBias;
434
435         /* Return the bias */
436         *pBias = timeZoneInformation.Bias;
437
438         /* Now determine if DST is being observed */
439
440         /* Get the UTC (GMT) time */
441         GetSystemTime(&utc);
442
443         /* Convert UTC time to local time using the time zone info.  If we are
444            observing DST, the calculated local time will include this. 
445         */
446         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
447
448         /* Set the daylight bias to 0.  The daylight bias is the amount of change
449            in time that we use for daylight savings time.  By setting this to 0
450            we cause there to be no change in time during daylight savings time. 
451         */
452         timeZoneInformation.DaylightBias = 0;
453
454         /* Convert the utc time to local time again, but this time without any
455            adjustment for daylight savings time. 
456         */
457         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
458
459         /* If the two times are different, then it means that the localDST that
460            we calculated includes the daylight bias, and therefore we are
461            observing daylight savings time.
462         */
463         *pDST = localDST.wHour != local.wHour;
464 }
465 #else
466 /* Determine if we are observing daylight savings time */
467 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
468 {
469         struct timeb t;
470
471         ftime(&t);
472         *pDST = t.dstflag;
473         *pDstBias = -60;    /* where can this be different? */
474         *pBias = t.timezone;
475 }
476 #endif /* DJGPP */
477  
478
479 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
480 {
481         BOOL dst;       /* Will be TRUE if observing DST */
482         LONG dstBias;   /* Offset from local time if observing DST */
483         LONG bias;      /* Offset from GMT for local time */
484
485         /*
486          * This function will adjust the last write time to compensate
487          * for two bugs in the smb client:
488          *
489          *    1) During Daylight Savings Time, the LastWriteTime is ahead
490          *       in time by the DaylightBias (ignoring the sign - the
491          *       DaylightBias is always stored as a negative number).  If
492          *       the DaylightBias is -60, then the LastWriteTime will be
493          *       ahead by 60 minutes.
494          *
495          *    2) If the local time zone is a positive offset from GMT, then
496          *       the LastWriteTime will be the correct local time plus the
497          *       Bias (ignoring the sign - a positive offset from GMT is
498          *       always stored as a negative Bias).  If the Bias is -120,
499          *       then the LastWriteTime will be ahead by 120 minutes.
500          *
501          *    These bugs can occur at the same time.
502          */
503
504         GetTimeZoneInfo(&dst, &dstBias, &bias);
505
506         /* First adjust for DST */
507         if (dst)
508                 *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
509
510         /* Now adjust for a positive offset from GMT (a negative bias). */
511         if (bias < 0)
512                 *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
513 }               
514
515 /*
516  * Calculate the difference (in seconds) between local time and GMT.
517  * This enables us to convert file times to kludge-GMT.
518  */
519 static void
520 smb_CalculateNowTZ()
521 {
522         time_t t;
523         struct tm gmt_tm, local_tm;
524         int days, hours, minutes, seconds;
525
526         t = time(NULL);
527         gmt_tm = *(gmtime(&t));
528         local_tm = *(localtime(&t));
529
530         days = local_tm.tm_yday - gmt_tm.tm_yday;
531         hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
532         minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
533         seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
534
535         smb_NowTZ = seconds;
536 }
537
538 #ifndef DJGPP
539 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
540 {
541         struct tm *ltp;
542         SYSTEMTIME stm;
543         struct tm localJunk;
544         long ersatz_unixTime;
545
546         /*
547          * Must use kludge-GMT instead of real GMT.
548          * kludge-GMT is computed by adding time zone difference to localtime.
549          *
550          * real GMT would be:
551          * ltp = gmtime(&unixTime);
552          */
553         ersatz_unixTime = unixTime - smb_NowTZ;
554         ltp = localtime(&ersatz_unixTime);
555
556         /* if we fail, make up something */
557         if (!ltp) {
558                 ltp = &localJunk;
559                 localJunk.tm_year = 89 - 20;
560                 localJunk.tm_mon = 4;
561                 localJunk.tm_mday = 12;
562                 localJunk.tm_hour = 0;
563                 localJunk.tm_min = 0;
564                 localJunk.tm_sec = 0;
565         }
566
567         stm.wYear = ltp->tm_year + 1900;
568         stm.wMonth = ltp->tm_mon + 1;
569         stm.wDayOfWeek = ltp->tm_wday;
570         stm.wDay = ltp->tm_mday;
571         stm.wHour = ltp->tm_hour;
572         stm.wMinute = ltp->tm_min;
573         stm.wSecond = ltp->tm_sec;
574         stm.wMilliseconds = 0;
575
576         SystemTimeToFileTime(&stm, largeTimep);
577 }
578 #else /* DJGPP */
579 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
580 {
581         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
582         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
583         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
584         LARGE_INTEGER ut;
585         int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
586
587         /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
588         *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
589                                    * 24 * 60);
590         *ft = LargeIntegerMultiplyByLong(*ft, 60);
591         *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
592
593         /* add unix time */
594         ut = ConvertLongToLargeInteger(unixTime);
595         ut = LargeIntegerMultiplyByLong(ut, 10000000);
596         *ft = LargeIntegerAdd(*ft, ut);
597 }
598 #endif /* !DJGPP */
599
600 #ifndef DJGPP
601 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
602 {
603         SYSTEMTIME stm;
604         struct tm lt;
605         long save_timezone;
606
607         FileTimeToSystemTime(largeTimep, &stm);
608
609         lt.tm_year = stm.wYear - 1900;
610         lt.tm_mon = stm.wMonth - 1;
611         lt.tm_wday = stm.wDayOfWeek;
612         lt.tm_mday = stm.wDay;
613         lt.tm_hour = stm.wHour;
614         lt.tm_min = stm.wMinute;
615         lt.tm_sec = stm.wSecond;
616         lt.tm_isdst = -1;
617
618         save_timezone = _timezone;
619         _timezone += smb_NowTZ;
620         *unixTimep = mktime(&lt);
621         _timezone = save_timezone;
622 }
623 #else /* DJGPP */
624 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
625 {
626         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
627         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
628         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
629         LARGE_INTEGER a;
630         int leap_years = 89;
631
632         /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
633         a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
634         a = LargeIntegerMultiplyByLong(a, 60);
635         a = LargeIntegerMultiplyByLong(a, 10000000);
636
637         /* subtract it from ft */
638         a = LargeIntegerSubtract(*ft, a);
639
640         /* divide down to seconds */
641         *unixTimep = LargeIntegerDivideByLong(a, 10000000);
642 }
643 #endif /* !DJGPP */
644
645 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
646 {
647         struct tm *ltp;
648         int dosDate;
649         int dosTime;
650         struct tm localJunk;
651
652         ltp = localtime((time_t*) &unixTime);
653
654         /* if we fail, make up something */
655         if (!ltp) {
656                 ltp = &localJunk;
657                 localJunk.tm_year = 89 - 20;
658                 localJunk.tm_mon = 4;
659                 localJunk.tm_mday = 12;
660                 localJunk.tm_hour = 0;
661                 localJunk.tm_min = 0;
662                 localJunk.tm_sec = 0;
663         }       
664
665         dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
666         dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
667         *dosTimep = (dosDate<<16) | dosTime;
668 }       
669
670 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
671 {
672         unsigned short dosDate;
673         unsigned short dosTime;
674         struct tm localTm;
675         
676         dosDate = searchTime & 0xffff;
677         dosTime = (searchTime >> 16) & 0xffff;
678         
679         localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
680         localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;    /* January is 0 in localTm */
681         localTm.tm_mday = (dosDate) & 0x1f;
682         localTm.tm_hour = (dosTime>>11) & 0x1f;
683         localTm.tm_min = (dosTime >> 5) & 0x3f;
684         localTm.tm_sec = (dosTime & 0x1f) * 2;
685         localTm.tm_isdst = -1;                          /* compute whether DST in effect */
686
687         *unixTimep = mktime(&localTm);
688 }
689
690 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
691 {
692         *dosUTimep = unixTime - smb_localZero;
693 }
694
695 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
696 {
697 #ifndef DJGPP
698         *unixTimep = dosTime + smb_localZero;
699 #else /* DJGPP */
700         /* dosTime seems to be already adjusted for GMT */
701         *unixTimep = dosTime;
702 #endif /* !DJGPP */
703 }
704
705 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
706 {
707         smb_vc_t *vcp;
708
709         lock_ObtainWrite(&smb_rctLock);
710         for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
711                 if (lsn == vcp->lsn && lana == vcp->lana) {
712                         vcp->refCount++;
713                         break;
714                 }
715         }
716         if (!vcp && (flags & SMB_FLAG_CREATE)) {
717                 vcp = malloc(sizeof(*vcp));
718                 memset(vcp, 0, sizeof(*vcp));
719                 vcp->refCount = 1;
720                 vcp->tidCounter = 1;
721                 vcp->fidCounter = 1;
722                 vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
723                 vcp->nextp = smb_allVCsp;
724                 smb_allVCsp = vcp;
725                 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
726                 vcp->lsn = lsn;
727                 vcp->lana = lana;
728         }
729         lock_ReleaseWrite(&smb_rctLock);
730         return vcp;
731 }
732
733 int smb_IsStarMask(char *maskp)
734 {
735         int i;
736         char tc;
737         
738         for(i=0; i<11; i++) {
739                 tc = *maskp++;
740                 if (tc == '?' || tc == '*' || tc == '>') return 1;        
741         }       
742         return 0;
743 }
744
745 void smb_ReleaseVC(smb_vc_t *vcp)
746 {
747         lock_ObtainWrite(&smb_rctLock);
748         osi_assert(vcp->refCount-- > 0);
749         lock_ReleaseWrite(&smb_rctLock);
750 }
751
752 void smb_HoldVC(smb_vc_t *vcp)
753 {
754         lock_ObtainWrite(&smb_rctLock);
755         vcp->refCount++;
756         lock_ReleaseWrite(&smb_rctLock);
757 }
758
759 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
760 {
761         smb_tid_t *tidp;
762
763         lock_ObtainWrite(&smb_rctLock);
764         for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
765                 if (tid == tidp->tid) {
766                         tidp->refCount++;
767                         break;
768                 }       
769         }
770         if (!tidp && (flags & SMB_FLAG_CREATE)) {
771                 tidp = malloc(sizeof(*tidp));
772                 memset(tidp, 0, sizeof(*tidp));
773                 tidp->nextp = vcp->tidsp;
774                 tidp->refCount = 1;
775                 tidp->vcp = vcp;
776                 vcp->tidsp = tidp;
777                 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
778                 tidp->tid = tid;
779         }
780         lock_ReleaseWrite(&smb_rctLock);
781         return tidp;
782 }       
783
784 void smb_ReleaseTID(smb_tid_t *tidp)
785 {
786         smb_tid_t *tp;
787         smb_tid_t **ltpp;
788         cm_user_t *userp;
789
790         userp = NULL;
791         lock_ObtainWrite(&smb_rctLock);
792         osi_assert(tidp->refCount-- > 0);
793         if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
794                 ltpp = &tidp->vcp->tidsp;
795                 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
796                         if (tp == tidp) break;
797                 }
798                 osi_assert(tp != NULL);
799                 *ltpp = tp->nextp;
800                 lock_FinalizeMutex(&tidp->mx);
801                 userp = tidp->userp;    /* remember to drop ref later */
802         }
803         lock_ReleaseWrite(&smb_rctLock);
804         if (userp) {
805                 cm_ReleaseUser(userp);
806         }       
807 }       
808
809 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
810 {
811         smb_user_t *uidp = NULL;
812
813         lock_ObtainWrite(&smb_rctLock);
814         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
815                 if (uid == uidp->userID) {
816                         uidp->refCount++;
817                         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 : "");
818                 break;
819                 }
820         }
821         if (!uidp && (flags & SMB_FLAG_CREATE)) {
822                 uidp = malloc(sizeof(*uidp));
823                 memset(uidp, 0, sizeof(*uidp));
824                 uidp->nextp = vcp->usersp;
825                 uidp->refCount = 1;
826                 uidp->vcp = vcp;
827                 vcp->usersp = uidp;
828                 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
829                 uidp->userID = uid;
830                 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 : ""));
831         }
832         lock_ReleaseWrite(&smb_rctLock);
833         return uidp;
834 }       
835
836 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
837 {
838         smb_username_t *unp= NULL;
839
840         lock_ObtainWrite(&smb_rctLock);
841         for(unp = usernamesp; unp; unp = unp->nextp) {
842                 if (stricmp(unp->name, usern) == 0 &&
843                         stricmp(unp->machine, machine) == 0) {
844                         unp->refCount++;
845                         break;
846                 }
847         }
848         if (!unp && (flags & SMB_FLAG_CREATE)) {
849                 unp = malloc(sizeof(*unp));
850                 memset(unp, 0, sizeof(*unp));
851                 unp->refCount = 1;
852                 unp->nextp = usernamesp;
853                 unp->name = strdup(usern);
854                 unp->machine = strdup(machine);
855                 usernamesp = unp;
856                 lock_InitializeMutex(&unp->mx, "username_t mutex");
857         }
858         lock_ReleaseWrite(&smb_rctLock);
859         return unp;
860 }       
861
862 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
863 {
864         smb_user_t *uidp= NULL;
865
866         lock_ObtainWrite(&smb_rctLock);
867         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
868                 if (!uidp->unp) 
869             continue;
870                 if (stricmp(uidp->unp->name, usern) == 0) {
871             uidp->refCount++;
872                         osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
873             break;
874                 } else
875             continue;
876         }       
877         lock_ReleaseWrite(&smb_rctLock);
878         return uidp;
879 }
880 void smb_ReleaseUID(smb_user_t *uidp)
881 {
882         smb_user_t *up;
883         smb_user_t **lupp;
884         cm_user_t *userp;
885
886         userp = NULL;
887         lock_ObtainWrite(&smb_rctLock);
888         osi_assert(uidp->refCount-- > 0);
889         if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
890                 lupp = &uidp->vcp->usersp;
891                 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
892                         if (up == uidp) break;
893                 }
894                 osi_assert(up != NULL);
895                 *lupp = up->nextp;
896                 lock_FinalizeMutex(&uidp->mx);
897                 if (uidp->unp)
898                         userp = uidp->unp->userp;       /* remember to drop ref later */
899         }               
900         lock_ReleaseWrite(&smb_rctLock);
901         if (userp) {
902                 cm_ReleaseUserVCRef(userp);
903                 cm_ReleaseUser(userp);
904         }       
905 }       
906
907 /* retrieve a held reference to a user structure corresponding to an incoming
908  * request.
909  * corresponding release function is cm_ReleaseUser.
910  */
911 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
912 {
913         smb_user_t *uidp;
914         cm_user_t *up;
915         smb_t *smbp;
916
917         smbp = (smb_t *) inp;
918         uidp = smb_FindUID(vcp, smbp->uid, 0);
919         if ((!uidp) ||  (!uidp->unp))
920                 return NULL;
921         
922         lock_ObtainMutex(&uidp->mx);
923         up = uidp->unp->userp;
924         cm_HoldUser(up);
925         lock_ReleaseMutex(&uidp->mx);
926
927         smb_ReleaseUID(uidp);
928         
929         return up;
930 }
931
932 /*
933  * Return a pointer to a pathname extracted from a TID structure.  The
934  * TID structure is not held; assume it won't go away.
935  */
936 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
937 {
938         smb_tid_t *tidp;
939         char *tpath;
940
941         tidp = smb_FindTID(vcp, tid, 0);
942     if (!tidp) 
943         return NULL;
944         tpath = tidp->pathname;
945         smb_ReleaseTID(tidp);
946         return tpath;
947 }
948
949 /* check to see if we have a chained fid, that is, a fid that comes from an
950  * OpenAndX message that ran earlier in this packet.  In this case, the fid
951  * field in a read, for example, request, isn't set, since the value is
952  * supposed to be inherited from the openAndX call.
953  */
954 int smb_ChainFID(int fid, smb_packet_t *inp)
955 {
956         if (inp->fid == 0 || inp->inCount == 0) 
957                 return fid;
958         else 
959                 return inp->fid;
960 }
961
962 /* are we a priv'd user?  What does this mean on NT? */
963 int smb_SUser(cm_user_t *userp)
964 {
965         return 1;
966 }
967
968 /* find a file ID.  If pass in 0, we'll allocate on on a create operation. */
969 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
970 {
971         smb_fid_t *fidp;
972         int newFid;
973         
974         /* figure out if we need to allocate a new file ID */
975         if (fid == 0) {
976                 newFid = 1;
977                 fid = vcp->fidCounter;
978         }
979         else newFid = 0;
980
981         lock_ObtainWrite(&smb_rctLock);
982 retry:
983         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
984                 if (fid == fidp->fid) {
985                         if (newFid) {
986                                 fid++;
987                 if (fid == 0) 
988                                         fid = 1;
989                 goto retry;
990             }
991                         fidp->refCount++;
992             break;
993                 }
994     }
995     if (!fidp && (flags & SMB_FLAG_CREATE)) {
996         char eventName[MAX_PATH];
997         sprintf(eventName,"fid_t event fid=%d", fid);
998                 fidp = malloc(sizeof(*fidp));
999         memset(fidp, 0, sizeof(*fidp));
1000                 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1001         fidp->refCount = 1;
1002         fidp->vcp = vcp;
1003         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1004         fidp->fid = fid;
1005                 fidp->curr_chunk = fidp->prev_chunk = -2;
1006                 fidp->raw_write_event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1007         if ( GetLastError() == ERROR_ALREADY_EXISTS )
1008             afsi_log("Event Object Already Exists: %s", eventName);
1009         if (newFid) {
1010                         vcp->fidCounter = fid+1;
1011             if (vcp->fidCounter == 0) vcp->fidCounter = 1;
1012         }
1013     }
1014     lock_ReleaseWrite(&smb_rctLock);
1015     return fidp;
1016 }
1017
1018 void smb_ReleaseFID(smb_fid_t *fidp)
1019 {
1020         cm_scache_t *scp;
1021     smb_vc_t *vcp;
1022     smb_ioctl_t *ioctlp;
1023
1024     if (!fidp)
1025         return;
1026
1027         scp = NULL;
1028         lock_ObtainWrite(&smb_rctLock);
1029         osi_assert(fidp->refCount-- > 0);
1030     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1031                 vcp = fidp->vcp;
1032                 if (!(fidp->flags & SMB_FID_IOCTL))
1033                         scp = fidp->scp;
1034                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1035                 thrd_CloseHandle(fidp->raw_write_event);
1036
1037                 /* and see if there is ioctl stuff to free */
1038         ioctlp = fidp->ioctlp;
1039         if (ioctlp) {
1040                         if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1041                         if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1042                         if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1043                         free(ioctlp);
1044         }
1045
1046         free(fidp);
1047     }
1048         lock_ReleaseWrite(&smb_rctLock);
1049
1050         /* now release the scache structure */
1051         if (scp) 
1052                 cm_ReleaseSCache(scp);
1053 }
1054
1055 /*
1056  * Case-insensitive search for one string in another;
1057  * used to find variable names in submount pathnames.
1058  */
1059 static char *smb_stristr(char *str1, char *str2)
1060 {
1061         char *cursor;
1062
1063         for (cursor = str1; *cursor; cursor++)
1064                 if (stricmp(cursor, str2) == 0)
1065                         return cursor;
1066
1067         return NULL;
1068 }
1069
1070 /*
1071  * Substitute a variable value for its name in a submount pathname.  Variable
1072  * name has been identified by smb_stristr() and is in substr.  Variable name
1073  * length (plus one) is in substr_size.  Variable value is in newstr.
1074  */
1075 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1076         char *newstr)
1077 {
1078         char temp[1024];
1079
1080         strcpy(temp, substr + substr_size - 1);
1081         strcpy(substr, newstr);
1082         strcat(str1, temp);
1083 }
1084
1085 char VNUserName[] = "%USERNAME%";
1086 char VNLCUserName[] = "%LCUSERNAME%";
1087 char VNComputerName[] = "%COMPUTERNAME%";
1088 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1089
1090 /* List available shares */
1091 int smb_ListShares()
1092 {
1093         char sbmtpath[256];
1094         char pathName[256];
1095         char shareBuf[4096];
1096         int num_shares=0;
1097         char *this_share;
1098         int len;
1099         char *p;
1100         int print_afs = 0;
1101         int code;
1102
1103         /*strcpy(shareNameList[num_shares], "all");
1104          strcpy(pathNameList[num_shares++], "/afs");*/
1105         fprintf(stderr, "The following shares are available:\n");
1106         fprintf(stderr, "Share Name (AFS Path)\n");
1107         fprintf(stderr, "---------------------\n");
1108         fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1109
1110 #ifndef DJGPP
1111         code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1112         if (code == 0 || code > sizeof(sbmtpath)) return -1;
1113 #else
1114         strcpy(sbmtpath, cm_confDir);
1115 #endif /* !DJGPP */
1116         strcat(sbmtpath, "/afsdsbmt.ini");
1117         len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1118                                                                    shareBuf, sizeof(shareBuf),
1119                                                                    sbmtpath);
1120         if (len == 0) {
1121                 return num_shares;
1122         }
1123
1124         this_share = shareBuf;
1125         do
1126         {
1127                 print_afs = 0;
1128                 /*strcpy(shareNameList[num_shares], this_share);*/
1129                 len = GetPrivateProfileString("AFS Submounts", this_share,
1130                                                                            NULL,
1131                                                                            pathName, 256,
1132                                                                            sbmtpath);
1133                 if (!len) 
1134                         return num_shares;
1135                 p = pathName;
1136                 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1137             print_afs = 1;
1138                 while (*p) {
1139             if (*p == '\\') *p = '/';    /* change to / */
1140             p++;
1141                 }
1142
1143                 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1144                                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1145                                  pathName);
1146                 num_shares++;
1147                 while (*this_share != 0) this_share++;  /* find next NUL */
1148                 this_share++;   /* skip past the NUL */
1149         } while (*this_share != 0);  /* stop at final NUL */
1150
1151         return num_shares;
1152 }
1153
1154 /* find a shareName in the table of submounts */
1155 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1156         char **pathNamep)
1157 {
1158         DWORD len;
1159         char pathName[1024];
1160         char *var;
1161         smb_user_t *uidp;
1162         char temp[1024];
1163         DWORD sizeTemp;
1164     char sbmtpath[MAX_PATH];
1165     char *p, *q;
1166         HKEY parmKey;
1167         DWORD code;
1168     DWORD allSubmount = 1;
1169
1170         if (strcmp(shareName, "IPC$") == 0) {
1171                 *pathNamep = NULL;
1172                 return 0;
1173         }
1174
1175     /* if allSubmounts == 0, only return the //mountRoot/all share 
1176      * if in fact it has been been created in the subMounts table.  
1177      * This is to allow sites that want to restrict access to the 
1178      * world to do so.
1179      */
1180         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1181                                                 0, KEY_QUERY_VALUE, &parmKey);
1182         if (code == ERROR_SUCCESS) {
1183         len = sizeof(allSubmount);
1184         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1185                                 (BYTE *) &allSubmount, &len);
1186         if (code != ERROR_SUCCESS) {
1187             allSubmount = 1;
1188         }
1189         RegCloseKey (parmKey);
1190         }
1191
1192         if (allSubmount && _stricmp(shareName, "all") == 0) {
1193                 *pathNamep = NULL;
1194                 return 1;
1195         }
1196
1197     /* In case, the all share is disabled we need to still be able
1198      * to handle ioctl requests 
1199      */
1200         if (_stricmp(shareName, "ioctl$") == 0) {
1201                 *pathNamep = strdup("/.__ioctl__");
1202                 return 1;
1203         }
1204
1205 #ifndef DJGPP
1206     strcpy(sbmtpath, "afsdsbmt.ini");
1207 #else /* DJGPP */
1208     strcpy(sbmtpath, cm_confDir);
1209     strcat(sbmtpath, "/afsdsbmt.ini");
1210 #endif /* !DJGPP */
1211         len = GetPrivateProfileString("AFS Submounts", shareName, "",
1212                                   pathName, sizeof(pathName), sbmtpath);
1213         if (len != 0 && len != sizeof(pathName) - 1) {
1214         /* We can accept either unix or PC style AFS pathnames.  Convert
1215          * Unix-style to PC style here for internal use. 
1216          */
1217         p = pathName;
1218         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1219             p += strlen(cm_mountRoot);  /* skip mount path */
1220         q = p;
1221         while (*q) {
1222             if (*q == '/') *q = '\\';    /* change to \ */
1223             q++;
1224         }
1225
1226         while (1)
1227         {
1228             if (var = smb_stristr(p, VNUserName)) {
1229                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1230                 if (uidp && uidp->unp)
1231                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1232                 else
1233                     smb_subst(p, var, sizeof(VNUserName)," ");
1234                 if (uidp)
1235                     smb_ReleaseUID(uidp);
1236             }
1237             else if (var = smb_stristr(p, VNLCUserName)) 
1238             {
1239                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1240                 if (uidp && uidp->unp)
1241                     strcpy(temp, uidp->unp->name);
1242                 else 
1243                     strcpy(temp, " ");
1244                 _strlwr(temp);
1245                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1246                 if (uidp)
1247                     smb_ReleaseUID(uidp);
1248             }
1249             else if (var = smb_stristr(p, VNComputerName)) 
1250             {
1251                 sizeTemp = sizeof(temp);
1252                 GetComputerName((LPTSTR)temp, &sizeTemp);
1253                 smb_subst(p, var, sizeof(VNComputerName), temp);
1254             }
1255             else if (var = smb_stristr(p, VNLCComputerName)) 
1256             {
1257                 sizeTemp = sizeof(temp);
1258                 GetComputerName((LPTSTR)temp, &sizeTemp);
1259                 _strlwr(temp);
1260                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1261             }
1262             else     
1263                 break;
1264         }
1265         *pathNamep = strdup(p);
1266         return 1;
1267     } 
1268     else /* create  \\<netbiosName>\<cellname>  */
1269     {
1270         if (cm_GetCell_Gen(shareName, temp, CM_FLAG_CREATE))
1271         {   
1272                         int len = min(strlen(shareName), strlen(temp));
1273             if (!_strnicmp(shareName, temp, len)) {  /* partial matches allowed */
1274                 sprintf(pathName,"/%s/",temp);
1275                 *pathNamep = strdup(strlwr(pathName));
1276                                 return 1;
1277             }
1278         } 
1279         }
1280     /* failure */
1281     *pathNamep = NULL;
1282     return 0;
1283 }
1284
1285 /* find a dir search structure by cookie value, and return it held.
1286  * Must be called with smb_globalLock held.
1287  */
1288 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1289 {
1290         smb_dirSearch_t *dsp;
1291         
1292         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1293                 if (dsp->cookie == cookie) {
1294                         if (dsp != smb_firstDirSearchp) {
1295                                 /* move to head of LRU queue, too, if we're not already there */
1296                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1297                                         smb_lastDirSearchp = (smb_dirSearch_t *)
1298                                                 osi_QPrev(&dsp->q);
1299                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1300                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1301                                 if (!smb_lastDirSearchp)
1302                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1303                         }
1304                         dsp->refCount++;
1305                         break;
1306                 }
1307         }
1308         return dsp;
1309 }
1310
1311 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1312 {
1313         lock_ObtainWrite(&smb_globalLock);
1314         dsp->flags |= SMB_DIRSEARCH_DELETE;
1315         lock_ReleaseWrite(&smb_globalLock);
1316         lock_ObtainMutex(&dsp->mx);
1317         if(dsp->scp != NULL) {
1318                 lock_ObtainMutex(&dsp->scp->mx);
1319                 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1320                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1321                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1322                     dsp->scp->bulkStatProgress = hones;
1323                 }       
1324                 lock_ReleaseMutex(&dsp->scp->mx);
1325         }       
1326         lock_ReleaseMutex(&dsp->mx);
1327 }
1328
1329 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1330 {
1331         cm_scache_t *scp;
1332         
1333         scp = NULL;
1334
1335         lock_ObtainWrite(&smb_globalLock);
1336         osi_assert(dsp->refCount-- > 0);
1337         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1338                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1339                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1340                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1341                 lock_FinalizeMutex(&dsp->mx);
1342                 scp = dsp->scp;
1343                 free(dsp);
1344         }
1345         lock_ReleaseWrite(&smb_globalLock);
1346
1347         /* do this now to avoid spurious locking hierarchy creation */
1348         if (scp) cm_ReleaseSCache(scp);
1349 }
1350
1351 /* find a dir search structure by cookie value, and return it held */
1352 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1353 {
1354         smb_dirSearch_t *dsp;
1355
1356         lock_ObtainWrite(&smb_globalLock);
1357         dsp = smb_FindDirSearchNL(cookie);
1358         lock_ReleaseWrite(&smb_globalLock);
1359         return dsp;
1360 }
1361
1362 /* GC some dir search entries, in the address space expected by the specific protocol.
1363  * Must be called with smb_globalLock held; release the lock temporarily.
1364  */
1365 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1366 void smb_GCDirSearches(int isV3)
1367 {
1368         smb_dirSearch_t *prevp;
1369         smb_dirSearch_t *tp;
1370         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1371         int victimCount;
1372         int i;
1373         
1374         victimCount = 0;        /* how many have we got so far */
1375         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1376                 /* we'll move tp from queue, so
1377                  * do this early.
1378                  */
1379                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1380                 /* if no one is using this guy, and we're either in the new protocol,
1381                  * or we're in the old one and this is a small enough ID to be useful
1382                  * to the old protocol, GC this guy.
1383                  */
1384                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1385                         /* hold and delete */
1386                         tp->flags |= SMB_DIRSEARCH_DELETE;
1387                         victimsp[victimCount++] = tp;
1388                         tp->refCount++;
1389                 }
1390
1391                 /* don't do more than this */
1392                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1393         }
1394         
1395         /* now release them */
1396         lock_ReleaseWrite(&smb_globalLock);
1397         for(i = 0; i < victimCount; i++) {
1398                 smb_ReleaseDirSearch(victimsp[i]);
1399         }
1400         lock_ObtainWrite(&smb_globalLock);
1401 }
1402
1403 /* function for allocating a dir search entry.  We need these to remember enough context
1404  * since we don't get passed the path from call to call during a directory search.
1405  *
1406  * Returns a held dir search structure, and bumps the reference count on the vnode,
1407  * since it saves a pointer to the vnode.
1408  */
1409 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1410 {
1411         smb_dirSearch_t *dsp;
1412         int counter;
1413         int maxAllowed;
1414
1415         lock_ObtainWrite(&smb_globalLock);
1416         counter = 0;
1417
1418         /* what's the biggest ID allowed in this version of the protocol */
1419         if (isV3) maxAllowed = 65535;
1420         else maxAllowed = 255;
1421
1422         while(1) {
1423                 /* twice so we have enough tries to find guys we GC after one pass;
1424                  * 10 extra is just in case I mis-counted.
1425                  */
1426                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1427                                                                                                         __FILE__, __LINE__);
1428                 if (smb_dirSearchCounter > maxAllowed) {        
1429                         smb_dirSearchCounter = 1;
1430                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
1431                 }       
1432                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1433                 if (dsp) {
1434                         /* don't need to watch for refcount zero and deleted, since
1435                          * we haven't dropped the global lock.
1436                          */
1437                         dsp->refCount--;
1438                         ++smb_dirSearchCounter;
1439                         continue;
1440                 }       
1441                 
1442                 dsp = malloc(sizeof(*dsp));
1443                 memset(dsp, 0, sizeof(*dsp));
1444                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1445                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1446                 dsp->cookie = smb_dirSearchCounter;
1447                 ++smb_dirSearchCounter;
1448                 dsp->refCount = 1;
1449                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1450                 dsp->lastTime = osi_Time();
1451                 break;
1452         }       
1453         lock_ReleaseWrite(&smb_globalLock);
1454         return dsp;
1455 }
1456
1457 static smb_packet_t *GetPacket(void)
1458 {
1459         smb_packet_t *tbp;
1460 #ifdef DJGPP
1461         unsigned int npar, seg, tb_sel;
1462 #endif
1463
1464         lock_ObtainWrite(&smb_globalLock);
1465         tbp = smb_packetFreeListp;
1466     if (tbp) 
1467         smb_packetFreeListp = tbp->nextp;
1468         lock_ReleaseWrite(&smb_globalLock);
1469     if (!tbp) {
1470 #ifndef DJGPP
1471         tbp = calloc(65540,1);
1472 #else /* DJGPP */
1473         tbp = malloc(sizeof(smb_packet_t));
1474 #endif /* !DJGPP */
1475         tbp->magic = SMB_PACKETMAGIC;
1476                 tbp->ncbp = NULL;
1477                 tbp->vcp = NULL;
1478                 tbp->resumeCode = 0;
1479                 tbp->inCount = 0;
1480                 tbp->fid = 0;
1481                 tbp->wctp = NULL;
1482                 tbp->inCom = 0;
1483                 tbp->oddByte = 0;
1484                 tbp->ncb_length = 0;
1485                 tbp->flags = 0;
1486         tbp->spacep = NULL;
1487         
1488 #ifdef DJGPP
1489         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1490         {
1491             signed int retval =
1492                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1493             if (retval == -1) {
1494                 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1495                           npar);
1496                 osi_panic("",__FILE__,__LINE__);
1497             }
1498             else {
1499                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1500                           npar, retval);
1501                 seg = retval;
1502             }
1503         }
1504         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1505         tbp->dos_pkt_sel = tb_sel;
1506 #endif /* DJGPP */
1507         }
1508     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1509
1510     return tbp;
1511 }
1512
1513 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1514 {
1515         smb_packet_t *tbp;
1516         tbp = GetPacket();
1517         memcpy(tbp, pkt, sizeof(smb_packet_t));
1518         tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1519         return tbp;
1520 }
1521
1522 static NCB *GetNCB(void)
1523 {
1524         smb_ncb_t *tbp;
1525     NCB *ncbp;
1526 #ifdef DJGPP
1527     unsigned int npar, seg, tb_sel;
1528 #endif /* DJGPP */
1529
1530         lock_ObtainWrite(&smb_globalLock);
1531         tbp = smb_ncbFreeListp;
1532     if (tbp) 
1533         smb_ncbFreeListp = tbp->nextp;
1534         lock_ReleaseWrite(&smb_globalLock);
1535     if (!tbp) {
1536 #ifndef DJGPP
1537         tbp = calloc(sizeof(*tbp),1);
1538 #else /* DJGPP */
1539         tbp = malloc(sizeof(*tbp));
1540         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1541         {
1542             signed int retval =
1543                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1544             if (retval == -1) {
1545                 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1546                           npar);
1547                 osi_panic("",__FILE__,__LINE__);
1548             } else {
1549                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1550                           npar, retval);
1551                 seg = retval;
1552             }
1553         }
1554         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1555         tbp->dos_ncb_sel = tb_sel;
1556 #endif /* !DJGPP */
1557         tbp->magic = SMB_NCBMAGIC;
1558         }
1559         
1560     osi_assert(tbp->magic == SMB_NCBMAGIC);
1561
1562         memset(&tbp->ncb, 0, sizeof(NCB));
1563     ncbp = &tbp->ncb;
1564 #ifdef DJGPP
1565     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1566 #endif /* DJGPP */
1567     return ncbp;
1568 }
1569
1570 void smb_FreePacket(smb_packet_t *tbp)
1571 {
1572     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1573         
1574     lock_ObtainWrite(&smb_globalLock);
1575         tbp->nextp = smb_packetFreeListp;
1576         smb_packetFreeListp = tbp;
1577         tbp->magic = SMB_PACKETMAGIC;
1578         tbp->ncbp = NULL;
1579         tbp->vcp = NULL;
1580         tbp->resumeCode = 0;
1581         tbp->inCount = 0;
1582         tbp->fid = 0;
1583         tbp->wctp = NULL;
1584         tbp->inCom = 0;
1585         tbp->oddByte = 0;
1586         tbp->ncb_length = 0;
1587         tbp->flags = 0;
1588     lock_ReleaseWrite(&smb_globalLock);
1589 }
1590
1591 static void FreeNCB(NCB *bufferp)
1592 {
1593         smb_ncb_t *tbp;
1594         
1595     tbp = (smb_ncb_t *) bufferp;
1596     osi_assert(tbp->magic == SMB_NCBMAGIC);
1597         
1598     lock_ObtainWrite(&smb_globalLock);
1599         tbp->nextp = smb_ncbFreeListp;
1600         smb_ncbFreeListp = tbp;
1601     lock_ReleaseWrite(&smb_globalLock);
1602 }
1603
1604 /* get a ptr to the data part of a packet, and its count */
1605 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1606 {
1607     int parmBytes;
1608     int dataBytes;
1609     unsigned char *afterParmsp;
1610
1611     parmBytes = *smbp->wctp << 1;
1612         afterParmsp = smbp->wctp + parmBytes + 1;
1613         
1614     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1615     if (nbytesp) *nbytesp = dataBytes;
1616         
1617         /* don't forget to skip the data byte count, since it follows
1618      * the parameters; that's where the "2" comes from below.
1619      */
1620     return (unsigned char *) (afterParmsp + 2);
1621 }
1622
1623 /* must set all the returned parameters before playing around with the
1624  * data region, since the data region is located past the end of the
1625  * variable number of parameters.
1626  */
1627 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1628 {
1629         unsigned char *afterParmsp;
1630
1631         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1632         
1633         *afterParmsp++ = dsize & 0xff;
1634         *afterParmsp = (dsize>>8) & 0xff;
1635 }
1636
1637 /* return the parm'th parameter in the smbp packet */
1638 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1639 {
1640         int parmCount;
1641         unsigned char *parmDatap;
1642
1643         parmCount = *smbp->wctp;
1644
1645         if (parm >= parmCount) {
1646 #ifndef DJGPP
1647         HANDLE h;
1648                 char *ptbuf[1];
1649                 char s[100];
1650                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1651                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1652                                 parm, parmCount, smbp->ncb_length);
1653                 ptbuf[0] = s;
1654                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1655                                         1, smbp->ncb_length, ptbuf, smbp);
1656                 DeregisterEventSource(h);
1657 #else /* DJGPP */
1658                 char s[100];
1659
1660                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1661                                 parm, parmCount, smbp->ncb_length);
1662                 osi_Log0(afsd_logp, s);
1663 #endif /* !DJGPP */
1664                 osi_panic(s, __FILE__, __LINE__);
1665         }
1666         parmDatap = smbp->wctp + (2*parm) + 1;
1667         
1668         return parmDatap[0] + (parmDatap[1] << 8);
1669 }
1670
1671 /* return the parm'th parameter in the smbp packet */
1672 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1673 {
1674         int parmCount;
1675         unsigned char *parmDatap;
1676
1677         parmCount = *smbp->wctp;
1678
1679         if (parm * 2 + offset >= parmCount * 2) {
1680 #ifndef DJGPP
1681                 HANDLE h;
1682                 char *ptbuf[1];
1683                 char s[100];
1684                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1685                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1686                                 parm, offset, parmCount, smbp->ncb_length);
1687                 ptbuf[0] = s;
1688                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1689                                         1, smbp->ncb_length, ptbuf, smbp);
1690                 DeregisterEventSource(h);
1691 #else /* DJGPP */
1692                 char s[100];
1693                 
1694                 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1695                                 "ncb len %d",
1696                                  parm, offset, parmCount, smbp->ncb_length);
1697                 osi_Log0(afsd_logp, s);
1698 #endif /* !DJGPP */
1699
1700                 osi_panic(s, __FILE__, __LINE__);
1701         }
1702         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1703         
1704         return parmDatap[0] + (parmDatap[1] << 8);
1705 }
1706
1707 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1708 {
1709         char *parmDatap;
1710
1711         /* make sure we have enough slots */
1712         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1713         
1714         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1715         *parmDatap++ = parmValue & 0xff;
1716         *parmDatap = (parmValue>>8) & 0xff;
1717 }
1718
1719 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1720 {
1721         char *parmDatap;
1722
1723         /* make sure we have enough slots */
1724         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1725
1726         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1727         *parmDatap++ = parmValue & 0xff;
1728         *parmDatap++ = (parmValue>>8) & 0xff;
1729         *parmDatap++ = (parmValue>>16) & 0xff;
1730         *parmDatap++ = (parmValue>>24) & 0xff;
1731 }
1732
1733 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1734 {
1735         char *parmDatap;
1736         int i;
1737
1738         /* make sure we have enough slots */
1739         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1740
1741         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1742         for (i=0; i<8; i++)
1743                 *parmDatap++ = *parmValuep++;
1744 }
1745
1746 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1747 {
1748         char *parmDatap;
1749
1750         /* make sure we have enough slots */
1751         if (*smbp->wctp <= slot) {
1752                 if (smbp->oddByte) {
1753                         smbp->oddByte = 0;
1754                         *smbp->wctp = slot+1;
1755                 } else
1756                         smbp->oddByte = 1;
1757         }
1758
1759         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1760         *parmDatap++ = parmValue & 0xff;
1761 }
1762
1763 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1764 {
1765         char *lastSlashp;
1766         
1767         lastSlashp = strrchr(inPathp, '\\');
1768         if (lastComponentp)
1769                 *lastComponentp = lastSlashp;
1770         if (lastSlashp) {
1771                 while (1) {
1772                         if (inPathp == lastSlashp) 
1773                                 break;
1774                         *outPathp++ = *inPathp++;
1775                 }
1776                 *outPathp++ = 0;
1777         }
1778         else {
1779                 *outPathp++ = 0;
1780         }
1781 }
1782
1783 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1784 {
1785         if (*inp++ != 0x4) 
1786                 return NULL;
1787         if (chainpp) {
1788                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1789         }
1790         return inp;
1791 }
1792
1793 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1794 {
1795         int tlen;
1796
1797         if (*inp++ != 0x5) 
1798                 return NULL;
1799         tlen = inp[0] + (inp[1]<<8);
1800         inp += 2;               /* skip length field */
1801         
1802         if (chainpp) {
1803                 *chainpp = inp + tlen;
1804         }
1805         
1806         if (lengthp) 
1807                 *lengthp = tlen;
1808         
1809         return inp;
1810 }       
1811
1812 /* format a packet as a response */
1813 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1814 {
1815         smb_t *outp;
1816         smb_t *inSmbp;
1817
1818         outp = (smb_t *) op;
1819         
1820         /* zero the basic structure through the smb_wct field, and zero the data
1821          * size field, assuming that wct stays zero; otherwise, you have to 
1822          * explicitly set the data size field, too.
1823          */
1824         inSmbp = (smb_t *) inp;
1825         memset(outp, 0, sizeof(smb_t)+2);
1826         outp->id[0] = 0xff;
1827         outp->id[1] = 'S';
1828         outp->id[2] = 'M';
1829         outp->id[3] = 'B';
1830         if (inp) {
1831                 outp->com = inSmbp->com;
1832                 outp->tid = inSmbp->tid;
1833                 outp->pid = inSmbp->pid;
1834                 outp->uid = inSmbp->uid;
1835                 outp->mid = inSmbp->mid;
1836                 outp->res[0] = inSmbp->res[0];
1837                 outp->res[1] = inSmbp->res[1];
1838                 op->inCom = inSmbp->com;
1839         }
1840         outp->reb = 0x80;       /* SERVER_RESP */
1841         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
1842
1843         /* copy fields in generic packet area */
1844         op->wctp = &outp->wct;
1845 }
1846
1847 /* send a (probably response) packet; vcp tells us to whom to send it.
1848  * we compute the length by looking at wct and bcc fields.
1849  */
1850 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1851 {
1852         NCB *ncbp;
1853         int extra;
1854         long code;
1855         unsigned char *tp;
1856         int localNCB = 0;
1857 #ifdef DJGPP
1858         dos_ptr dos_ncb;
1859 #endif /* DJGPP */
1860         
1861         ncbp = inp->ncbp;
1862         if (ncbp == NULL) {
1863                 ncbp = GetNCB();
1864                 localNCB = 1;
1865         }
1866 #ifdef DJGPP
1867         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1868 #endif /* DJGPP */
1869  
1870         memset((char *)ncbp, 0, sizeof(NCB));
1871
1872         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
1873         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
1874         extra += tp[0] + (tp[1]<<8);
1875         extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);   /* distance to last wct field */
1876         extra += 3;                     /* wct and length fields */
1877         
1878         ncbp->ncb_length = extra;       /* bytes to send */
1879         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
1880         ncbp->ncb_lana_num = vcp->lana;
1881         ncbp->ncb_command = NCBSEND;    /* op means send data */
1882 #ifndef DJGPP
1883         ncbp->ncb_buffer = (char *) inp;/* packet */
1884         code = Netbios(ncbp);
1885 #else /* DJGPP */
1886         ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1887         ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1888
1889         /* copy header information from virtual to DOS address space */
1890         dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1891         code = Netbios(ncbp, dos_ncb);
1892 #endif /* !DJGPP */
1893         
1894         if (code != 0)
1895                 osi_Log1(afsd_logp, "SendPacket failure code %d", code);
1896
1897         if (localNCB)
1898                 FreeNCB(ncbp);
1899 }
1900
1901 void smb_MapNTError(long code, unsigned long *NTStatusp)
1902 {
1903         unsigned long NTStatus;
1904
1905         /* map CM_ERROR_* errors to NT 32-bit status codes */
1906         if (code == CM_ERROR_NOSUCHCELL) {
1907                 NTStatus = 0xC000000FL; /* No such file */
1908         }
1909         else if (code == CM_ERROR_NOSUCHVOLUME) {
1910                 NTStatus = 0xC000000FL; /* No such file */
1911         }
1912         else if (code == CM_ERROR_TIMEDOUT) {
1913                 NTStatus = 0xC00000CFL; /* Sharing Paused */
1914         }
1915         else if (code == CM_ERROR_RETRY) {
1916                 NTStatus = 0xC000022DL; /* Retry */
1917         }
1918         else if (code == CM_ERROR_NOACCESS) {
1919                 NTStatus = 0xC0000022L; /* Access denied */
1920         }
1921         else if (code == CM_ERROR_READONLY) {
1922                 NTStatus = 0xC00000A2L; /* Write protected */
1923         }       
1924         else if (code == CM_ERROR_NOSUCHFILE) {
1925                 NTStatus = 0xC000000FL; /* No such file */
1926         }
1927         else if (code == CM_ERROR_NOSUCHPATH) {
1928                 NTStatus = 0xC000003AL; /* Object path not found */
1929         }               
1930         else if (code == CM_ERROR_TOOBIG) {
1931                 NTStatus = 0xC000007BL; /* Invalid image format */
1932         }
1933         else if (code == CM_ERROR_INVAL) {
1934                 NTStatus = 0xC000000DL; /* Invalid parameter */
1935         }
1936         else if (code == CM_ERROR_BADFD) {
1937                 NTStatus = 0xC0000008L; /* Invalid handle */
1938         }
1939         else if (code == CM_ERROR_BADFDOP) {
1940                 NTStatus = 0xC0000022L; /* Access denied */
1941         }
1942         else if (code == CM_ERROR_EXISTS) {
1943                 NTStatus = 0xC0000035L; /* Object name collision */
1944         }
1945         else if (code == CM_ERROR_NOTEMPTY) {
1946                 NTStatus = 0xC0000101L; /* Directory not empty */
1947         }       
1948         else if (code == CM_ERROR_CROSSDEVLINK) {
1949                 NTStatus = 0xC00000D4L; /* Not same device */
1950         }
1951         else if (code == CM_ERROR_NOTDIR) {
1952                 NTStatus = 0xC0000103L; /* Not a directory */
1953         }
1954         else if (code == CM_ERROR_ISDIR) {
1955                 NTStatus = 0xC00000BAL; /* File is a directory */
1956         }
1957         else if (code == CM_ERROR_BADOP) {
1958                 NTStatus = 0xC09820FFL; /* SMB no support */
1959         }
1960         else if (code == CM_ERROR_BADSHARENAME) {
1961                 NTStatus = 0xC00000CCL; /* Bad network name */
1962         }
1963         else if (code == CM_ERROR_NOIPC) {
1964 #ifdef COMMENT
1965                 NTStatus = 0xC0000022L; /* Access Denied */
1966 #else
1967         NTStatus = 0xC000013DL; /* Remote Resources */
1968 #endif
1969         }
1970         else if (code == CM_ERROR_CLOCKSKEW) {
1971                 NTStatus = 0xC0000133L; /* Time difference at DC */
1972         }
1973         else if (code == CM_ERROR_BADTID) {
1974                 NTStatus = 0xC0982005L; /* SMB bad TID */
1975         }
1976         else if (code == CM_ERROR_USESTD) {
1977                 NTStatus = 0xC09820FBL; /* SMB use standard */
1978         }
1979         else if (code == CM_ERROR_QUOTA) {
1980                 NTStatus = 0xC0000044L; /* Quota exceeded */
1981         }
1982         else if (code == CM_ERROR_SPACE) {
1983                 NTStatus = 0xC000007FL; /* Disk full */
1984         }
1985         else if (code == CM_ERROR_ATSYS) {
1986                 NTStatus = 0xC0000033L; /* Object name invalid */
1987         }
1988         else if (code == CM_ERROR_BADNTFILENAME) {
1989                 NTStatus = 0xC0000033L; /* Object name invalid */
1990         }
1991         else if (code == CM_ERROR_WOULDBLOCK) {
1992                 NTStatus = 0xC0000055L; /* Lock not granted */
1993         }
1994         else if (code == CM_ERROR_PARTIALWRITE) {
1995                 NTStatus = 0xC000007FL; /* Disk full */
1996         }
1997         else if (code == CM_ERROR_BUFFERTOOSMALL) {
1998                 NTStatus = 0xC0000023L; /* Buffer too small */
1999         }
2000         else {
2001                 NTStatus = 0xC0982001L; /* SMB non-specific error */
2002         }
2003
2004         *NTStatusp = NTStatus;
2005         osi_Log2(afsd_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2006 }
2007
2008 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2009         unsigned char *classp)
2010 {
2011         unsigned char class;
2012         unsigned short error;
2013
2014         /* map CM_ERROR_* errors to SMB errors */
2015         if (code == CM_ERROR_NOSUCHCELL) {
2016                 class = 1;
2017                 error = 3;      /* bad path */
2018         }
2019         else if (code == CM_ERROR_NOSUCHVOLUME) {
2020                 class = 1;
2021                 error = 3;      /* bad path */
2022         }
2023         else if (code == CM_ERROR_TIMEDOUT) {
2024                 class = 2;
2025                 error = 81;     /* server is paused */
2026         }
2027         else if (code == CM_ERROR_RETRY) {
2028                 class = 2;      /* shouldn't happen */
2029                 error = 1;
2030         }
2031         else if (code == CM_ERROR_NOACCESS) {
2032                 class = 2;
2033                 error = 4;      /* bad access */
2034         }
2035         else if (code == CM_ERROR_READONLY) {
2036                 class = 3;
2037                 error = 19;     /* read only */
2038         }
2039         else if (code == CM_ERROR_NOSUCHFILE) {
2040                 class = 1;
2041                 error = 2;      /* ENOENT! */
2042         }
2043         else if (code == CM_ERROR_NOSUCHPATH) {
2044                 class = 1;
2045                 error = 3;      /* Bad path */
2046         }
2047         else if (code == CM_ERROR_TOOBIG) {
2048                 class = 1;
2049                 error = 11;     /* bad format */
2050         }
2051         else if (code == CM_ERROR_INVAL) {
2052                 class = 2;      /* server non-specific error code */
2053                 error = 1;
2054         }
2055         else if (code == CM_ERROR_BADFD) {
2056                 class = 1;
2057                 error = 6;      /* invalid file handle */
2058         }
2059         else if (code == CM_ERROR_BADFDOP) {
2060                 class = 1;      /* invalid op on FD */
2061                 error = 5;
2062         }
2063         else if (code == CM_ERROR_EXISTS) {
2064                 class = 1;
2065                 error = 80;     /* file already exists */
2066         }
2067         else if (code == CM_ERROR_NOTEMPTY) {
2068                 class = 1;
2069                 error = 5;      /* delete directory not empty */
2070         }
2071         else if (code == CM_ERROR_CROSSDEVLINK) {
2072                 class = 1;
2073                 error = 17;     /* EXDEV */
2074         }
2075         else if (code == CM_ERROR_NOTDIR) {
2076                 class = 1;      /* bad path */
2077                 error = 3;
2078         }
2079         else if (code == CM_ERROR_ISDIR) {
2080                 class = 1;      /* access denied; DOS doesn't have a good match */
2081                 error = 5;
2082         }
2083         else if (code == CM_ERROR_BADOP) {
2084                 class = 2;
2085                 error = 65535;
2086         }
2087         else if (code == CM_ERROR_BADSHARENAME) {
2088                 class = 2;
2089                 error = 6;
2090         }
2091         else if (code == CM_ERROR_NOIPC) {
2092                 class = 2;
2093                 error = 4; /* bad access */
2094         }
2095         else if (code == CM_ERROR_CLOCKSKEW) {
2096                 class = 1;      /* invalid function */
2097                 error = 1;
2098         }
2099         else if (code == CM_ERROR_BADTID) {
2100                 class = 2;
2101                 error = 5;
2102         }
2103         else if (code == CM_ERROR_USESTD) {
2104                 class = 2;
2105                 error = 251;
2106         }
2107         else if (code == CM_ERROR_REMOTECONN) {
2108                 class = 2;
2109                 error = 82;
2110         }
2111         else if (code == CM_ERROR_QUOTA) {
2112                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2113                         class = 3;
2114                         error = 39;     /* disk full */
2115                 }
2116                 else {
2117                         class = 1;
2118                         error = 5;      /* access denied */
2119                 }
2120         }
2121         else if (code == CM_ERROR_SPACE) {
2122                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2123                         class = 3;
2124                         error = 39;     /* disk full */
2125                 }
2126                 else {
2127                         class = 1;
2128                         error = 5;      /* access denied */
2129                 }
2130         }
2131         else if (code == CM_ERROR_PARTIALWRITE) {
2132                 class = 3;
2133                 error = 39;     /* disk full */
2134         }
2135         else if (code == CM_ERROR_ATSYS) {
2136                 class = 1;
2137                 error = 2;      /* ENOENT */
2138         }
2139         else if (code == CM_ERROR_WOULDBLOCK) {
2140                 class = 1;
2141                 error = 33;     /* lock conflict */
2142         }
2143         else if (code == CM_ERROR_NOFILES) {
2144                 class = 1;
2145                 error = 18;     /* no files in search */
2146         }
2147         else if (code == CM_ERROR_RENAME_IDENTICAL) {
2148                 class = 1;
2149                 error = 183;     /* Samba uses this */
2150         }
2151         else {
2152                 class = 2;
2153                 error = 1;
2154         }
2155
2156         *scodep = error;
2157         *classp = class;
2158         osi_Log3(afsd_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2159 }
2160
2161 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2162 {
2163         return CM_ERROR_BADOP;
2164 }
2165
2166 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2167 {
2168         unsigned short EchoCount, i;
2169         char *data, *outdata;
2170         int dataSize;
2171
2172         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2173
2174         for (i=1; i<=EchoCount; i++) {
2175             data = smb_GetSMBData(inp, &dataSize);
2176             smb_SetSMBParm(outp, 0, i);
2177             smb_SetSMBDataLength(outp, dataSize);
2178             outdata = smb_GetSMBData(outp, NULL);
2179             memcpy(outdata, data, dataSize);
2180             smb_SendPacket(vcp, outp);
2181         }
2182
2183         return 0;
2184 }
2185
2186 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2187 {
2188         osi_hyper_t offset;
2189         long count, minCount, finalCount;
2190         unsigned short fd;
2191         smb_fid_t *fidp;
2192         long code;
2193         cm_user_t *userp = NULL;
2194     NCB *ncbp;
2195     int rc;
2196 #ifndef DJGPP
2197     char *rawBuf = NULL;
2198 #else
2199     dos_ptr rawBuf = NULL;
2200     dos_ptr dos_ncb;
2201 #endif /* DJGPP */
2202
2203         rawBuf = NULL;
2204         finalCount = 0;
2205
2206         fd = smb_GetSMBParm(inp, 0);
2207         count = smb_GetSMBParm(inp, 3);
2208         minCount = smb_GetSMBParm(inp, 4);
2209         offset.HighPart = 0;    /* too bad */
2210         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2211
2212         osi_Log3(afsd_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2213              fd, offset.LowPart, count);
2214
2215         fidp = smb_FindFID(vcp, fd, 0);
2216         if (!fidp)
2217                 goto send1;
2218
2219         lock_ObtainMutex(&smb_RawBufLock);
2220         if (smb_RawBufs) {
2221                 /* Get a raw buf, from head of list */
2222                 rawBuf = smb_RawBufs;
2223 #ifndef DJGPP
2224                 smb_RawBufs = *(char **)smb_RawBufs;
2225 #else /* DJGPP */
2226         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2227 #endif /* !DJGPP */
2228         }
2229         lock_ReleaseMutex(&smb_RawBufLock);
2230         if (!rawBuf)
2231                 goto send1a;
2232
2233     if (fidp->flags & SMB_FID_IOCTL)
2234     {
2235 #ifndef DJGPP
2236         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2237 #else
2238         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2239 #endif
2240         if (rawBuf) {
2241             /* Give back raw buffer */
2242             lock_ObtainMutex(&smb_RawBufLock);
2243 #ifndef DJGPP
2244             *((char **) rawBuf) = smb_RawBufs;
2245 #else /* DJGPP */
2246             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2247 #endif /* !DJGPP */
2248             
2249             smb_RawBufs = rawBuf;
2250             lock_ReleaseMutex(&smb_RawBufLock);
2251         }
2252
2253         smb_ReleaseFID(fidp);
2254         return rc;
2255     }
2256         
2257     userp = smb_GetUser(vcp, inp);
2258
2259 #ifndef DJGPP
2260         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2261 #else /* DJGPP */
2262     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2263     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2264                         userp, &finalCount, TRUE /* rawFlag */);
2265 #endif /* !DJGPP */
2266
2267         if (code != 0)
2268                 goto send;
2269
2270   send:
2271     cm_ReleaseUser(userp);
2272
2273   send1a:
2274         smb_ReleaseFID(fidp);
2275
2276   send1:
2277         ncbp = outp->ncbp;
2278 #ifdef DJGPP
2279     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2280 #endif /* DJGPP */
2281         memset((char *)ncbp, 0, sizeof(NCB));
2282
2283         ncbp->ncb_length = (unsigned short) finalCount;
2284         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2285         ncbp->ncb_lana_num = vcp->lana;
2286         ncbp->ncb_command = NCBSEND;
2287         ncbp->ncb_buffer = rawBuf;
2288
2289 #ifndef DJGPP
2290         code = Netbios(ncbp);
2291 #else /* DJGPP */
2292         code = Netbios(ncbp, dos_ncb);
2293 #endif /* !DJGPP */
2294         if (code != 0)
2295                 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
2296
2297         if (rawBuf) {
2298                 /* Give back raw buffer */
2299                 lock_ObtainMutex(&smb_RawBufLock);
2300 #ifndef DJGPP
2301                 *((char **) rawBuf) = smb_RawBufs;
2302 #else /* DJGPP */
2303         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2304 #endif /* !DJGPP */
2305
2306                 smb_RawBufs = rawBuf;
2307                 lock_ReleaseMutex(&smb_RawBufLock);
2308         }
2309
2310         return 0;
2311 }
2312
2313 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2314 {
2315         return 0;
2316 }
2317
2318 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2319 {
2320         return 0;
2321 }
2322
2323 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2324 {
2325         char *namep;
2326         int coreProtoIndex;
2327         int v3ProtoIndex;
2328         int NTProtoIndex;
2329         int protoIndex;                 /* index we're using */
2330         int namex;
2331         int dbytes;
2332         int entryLength;
2333         int tcounter;
2334         char protocol_array[10][1024]; /* protocol signature of the client */
2335
2336         
2337         osi_Log1(afsd_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2338                          ongoingOps - 1);
2339         if (!isGateway) {
2340                 if (active_vcp) {
2341                         DWORD now = GetCurrentTime();
2342                         if (now - last_msg_time >= 30000
2343                                 && now - last_msg_time <= 90000) {
2344                                 osi_Log1(afsd_logp,
2345                                                  "Setting dead_vcp %x", active_vcp);
2346                                 dead_vcp = active_vcp;
2347                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2348                         }
2349                 }
2350         }
2351
2352         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2353
2354         namep = smb_GetSMBData(inp, &dbytes);
2355         namex = 0;
2356         tcounter = 0;
2357         coreProtoIndex = -1;            /* not found */
2358         v3ProtoIndex = -1;
2359         NTProtoIndex = -1;
2360         while(namex < dbytes) {
2361                 osi_Log1(afsd_logp, "Protocol %s",
2362                                  osi_LogSaveString(afsd_logp, namep+1));
2363                 strcpy(protocol_array[tcounter], namep+1);
2364
2365                 /* namep points at the first protocol, or really, a 0x02
2366                  * byte preceding the null-terminated ASCII name.
2367                  */
2368                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2369                         coreProtoIndex = tcounter;
2370                 }       
2371                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2372                         v3ProtoIndex = tcounter;
2373                 }
2374                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2375                         NTProtoIndex = tcounter;
2376                 }
2377
2378                 /* compute size of protocol entry */
2379                 entryLength = strlen(namep+1);
2380         entryLength += 2;       /* 0x02 bytes and null termination */
2381                 
2382         /* advance over this protocol entry */
2383                 namex += entryLength;
2384         namep += entryLength;
2385         tcounter++;             /* which proto entry we're looking at */
2386         }
2387 #ifndef NOMOREFILESFIX
2388         /* 
2389          * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2390          * the client is running by reading the protocol signature.
2391          * ie. the order in which it sends us the protocol list.
2392          *
2393          * Special handling for Windows 2000 clients (defect 11765 )
2394      * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2395          */
2396         if (tcounter == 6) {
2397                 int i = 0;
2398                 smb_t *ip = (smb_t *) inp;
2399                 smb_t *op = (smb_t *) outp;
2400
2401                 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2402                          (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2403                          (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2404                          (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2405                          (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2406                          (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2407                         isWindows2000 = TRUE;
2408                         osi_Log0(afsd_logp, "Looks like a Windows 2000 client");
2409                         /* 
2410                          * HACK: for now - just negotiate a lower protocol till we 
2411                          * figure out which flag/flag2 or some other field 
2412                          * (capabilities maybe?) to set in order for this to work
2413                          * correctly with Windows 2000 clients (defect 11765)
2414                          */
2415                         NTProtoIndex = -1;
2416                         /* Things to try (after looking at tcpdump output could be
2417                          * setting flags and flags2 to 0x98 and 0xc853 like this
2418                          * op->reb = 0x98; op->flg2 = 0xc853;
2419                          * osi_Log2(afsd_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2420                          */
2421                 }       
2422         }       
2423 #endif /* NOMOREFILESFIX */
2424
2425         if (NTProtoIndex != -1) {
2426                 protoIndex = NTProtoIndex;
2427                 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2428         }
2429         else if (v3ProtoIndex != -1) {
2430                 protoIndex = v3ProtoIndex;
2431                 vcp->flags |= SMB_VCFLAG_USEV3;
2432         }       
2433         else if (coreProtoIndex != -1) {
2434                 protoIndex = coreProtoIndex;
2435                 vcp->flags |= SMB_VCFLAG_USECORE;
2436         }       
2437         else protoIndex = -1;
2438
2439         if (protoIndex == -1)
2440                 return CM_ERROR_INVAL;
2441         else if (NTProtoIndex != -1) {
2442                 smb_SetSMBParm(outp, 0, protoIndex);
2443         smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2444         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2445         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2446         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2447                 smb_SetSMBParmLong(outp, 5, 65536);     /* raw buffer size */
2448         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2449         smb_SetSMBParm(outp, 8, 1);
2450                 /* 
2451                  * Tried changing the capabilities to support for W2K - defect 117695
2452                  * Maybe something else needs to be changed here?
2453                  */
2454                 /*
2455                   if (isWindows2000) 
2456                   smb_SetSMBParmLong(outp, 9, 0x43fd);
2457                   else 
2458                   smb_SetSMBParmLong(outp, 9, 0x251);
2459                   */
2460                 /* Capabilities: *
2461                  * 32-bit error codes *
2462                  * and NT Find *
2463                  * and NT SMB's *
2464                  * and raw mode */
2465                 smb_SetSMBParmLong(outp, 9, 0x251);     
2466                 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2467                 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2468                 smb_SetSMBParm(outp, 15, 0);    /* XXX server tzone: do we need? */
2469                 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2470                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2471         }
2472         else if (v3ProtoIndex != -1) {
2473                 smb_SetSMBParm(outp, 0, protoIndex);
2474                 smb_SetSMBParm(outp, 1, 0);     /* share level security, no passwd encrypt */
2475                 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2476                 smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2477                 smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2478                 smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2479                 smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2480                 smb_SetSMBParm(outp, 7, 1);
2481                 smb_SetSMBParm(outp, 8, 0);     /* XXX server time: do we need? */
2482                 smb_SetSMBParm(outp, 9, 0);     /* XXX server date: do we need? */
2483                 smb_SetSMBParm(outp, 10, 0);    /* XXX server tzone: do we need? */
2484                 smb_SetSMBParm(outp, 11, 0);    /* resvd */
2485                 smb_SetSMBParm(outp, 12, 0);    /* resvd */
2486                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2487         }
2488         else if (coreProtoIndex != -1) {
2489                 smb_SetSMBParm(outp, 0, protoIndex);
2490                 smb_SetSMBDataLength(outp, 0);
2491         }
2492         return 0;
2493 }
2494
2495 void smb_Daemon(void *parmp)
2496 {
2497         int count = 0;
2498
2499         while(1) {
2500                 count++;
2501                 thrd_Sleep(10000);
2502                 if ((count % 360) == 0)         /* every hour */
2503                         smb_CalculateNowTZ();
2504                 /* XXX GC dir search entries */
2505         }
2506 }
2507
2508 void smb_WaitingLocksDaemon()
2509 {
2510         smb_waitingLock_t *wL, *nwL;
2511         int first;
2512         smb_vc_t *vcp;
2513         smb_packet_t *inp, *outp;
2514         NCB *ncbp;
2515         long code;
2516
2517         while(1) {
2518                 lock_ObtainWrite(&smb_globalLock);
2519                 nwL = smb_allWaitingLocks;
2520                 if (nwL == NULL) {
2521                         osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2522                         thrd_Sleep(1000);
2523                         continue;
2524                 }
2525                 else first = 1;
2526                 do {
2527                         if (first)
2528                                 first = 0;
2529                         else
2530                                 lock_ObtainWrite(&smb_globalLock);
2531                         wL = nwL;
2532                         nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2533                         lock_ReleaseWrite(&smb_globalLock);
2534                         code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2535                                                                 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2536                         if (code == CM_ERROR_WOULDBLOCK) {
2537                                 /* no progress */
2538                                 if (wL->timeRemaining != 0xffffffff
2539                                     && (wL->timeRemaining -= 1000) < 0)
2540                                         goto endWait;
2541                                 continue;
2542                         }
2543                   endWait:
2544                         vcp = wL->vcp;
2545                         inp = wL->inp;
2546                         outp = wL->outp;
2547                         ncbp = GetNCB();
2548                         ncbp->ncb_length = inp->ncb_length;
2549                         inp->spacep = cm_GetSpace();
2550
2551                         /* Remove waitingLock from list */
2552                         lock_ObtainWrite(&smb_globalLock);
2553                         osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2554                                     &wL->q);
2555                         lock_ReleaseWrite(&smb_globalLock);
2556
2557                         /* Resume packet processing */
2558                         if (code == 0)
2559                                 smb_SetSMBDataLength(outp, 0);
2560                         outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2561                         outp->resumeCode = code;
2562                         outp->ncbp = ncbp;
2563                         smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2564
2565                         /* Clean up */
2566                         cm_FreeSpace(inp->spacep);
2567                         smb_FreePacket(inp);
2568                         smb_FreePacket(outp);
2569                         FreeNCB(ncbp);
2570                         free(wL);
2571                 } while (nwL);
2572                 thrd_Sleep(1000);
2573         }
2574 }
2575
2576 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2577 {
2578         osi_Log0(afsd_logp, "SMB receive get disk attributes");
2579
2580         smb_SetSMBParm(outp, 0, 32000);
2581         smb_SetSMBParm(outp, 1, 64);
2582         smb_SetSMBParm(outp, 2, 1024);
2583         smb_SetSMBParm(outp, 3, 30000);
2584         smb_SetSMBParm(outp, 4, 0);
2585         smb_SetSMBDataLength(outp, 0);
2586         return 0;
2587 }
2588
2589 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2590 {
2591         smb_tid_t *tidp;
2592         unsigned short newTid;
2593         char shareName[256];
2594         char *sharePath;
2595         int shareFound;
2596         char *tp;
2597         char *pathp;
2598         char *passwordp;
2599         cm_user_t *userp;
2600
2601         osi_Log0(afsd_logp, "SMB receive tree connect");
2602
2603         /* parse input parameters */
2604         tp = smb_GetSMBData(inp, NULL);
2605         pathp = smb_ParseASCIIBlock(tp, &tp);
2606         passwordp = smb_ParseASCIIBlock(tp, &tp);
2607         tp = strrchr(pathp, '\\');
2608         if (!tp)
2609                 return CM_ERROR_BADSMB;
2610         strcpy(shareName, tp+1);
2611
2612         userp = smb_GetUser(vcp, inp);
2613
2614         lock_ObtainMutex(&vcp->mx);
2615         newTid = vcp->tidCounter++;
2616         lock_ReleaseMutex(&vcp->mx);
2617         
2618         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2619         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2620         if (!shareFound) {
2621                 smb_ReleaseTID(tidp);
2622                 return CM_ERROR_BADSHARENAME;
2623         }
2624         lock_ObtainMutex(&tidp->mx);
2625         tidp->userp = userp;
2626         tidp->pathname = sharePath;
2627         lock_ReleaseMutex(&tidp->mx);
2628         smb_ReleaseTID(tidp);
2629
2630         smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2631         smb_SetSMBParm(rsp, 1, newTid);
2632         smb_SetSMBDataLength(rsp, 0);
2633
2634         osi_Log1(afsd_logp, "SMB tree connect created ID %d", newTid);
2635         return 0;
2636 }
2637
2638 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2639 {
2640         int tlen;
2641
2642         if (*inp++ != 0x1) return NULL;
2643         tlen = inp[0] + (inp[1]<<8);
2644         inp += 2;               /* skip length field */
2645         
2646         if (chainpp) {
2647                 *chainpp = inp + tlen;
2648         }       
2649         
2650         if (lengthp) *lengthp = tlen;
2651         
2652         return inp;
2653 }
2654
2655 /* set maskp to the mask part of the incoming path.
2656  * Mask is 11 bytes long (8.3 with the dot elided).
2657  * Returns true if succeeds with a valid name, otherwise it does
2658  * its best, but returns false.
2659  */
2660 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2661 {
2662         char *tp;
2663         char *up;
2664         int i;
2665         int tc;
2666         int valid8Dot3;
2667
2668         /* starts off valid */
2669         valid8Dot3 = 1;
2670
2671         /* mask starts out all blanks */
2672         memset(maskp, ' ', 11);
2673
2674         /* find last backslash, or use whole thing if there is none */
2675         tp = strrchr(pathp, '\\');
2676         if (!tp) tp = pathp;
2677         else tp++;      /* skip slash */
2678         
2679         up = maskp;
2680
2681         /* names starting with a dot are illegal */
2682         if (*tp == '.') valid8Dot3 = 0;
2683
2684     for(i=0;; i++) {
2685                 tc = *tp++;
2686         if (tc == 0) return valid8Dot3;
2687         if (tc == '.' || tc == '"') break;
2688         if (i < 8) *up++ = tc;
2689         else valid8Dot3 = 0;
2690     }
2691         
2692     /* if we get here, tp point after the dot */
2693     up = maskp+8;       /* ext goes here */
2694     for(i=0;;i++) {
2695         tc = *tp++;
2696         if (tc == 0) 
2697                         return valid8Dot3;
2698
2699         /* too many dots */
2700         if (tc == '.' || tc == '"') 
2701                         valid8Dot3 = 0;
2702
2703         /* copy extension if not too long */
2704         if (i < 3) 
2705                         *up++ = tc;
2706         else 
2707                         valid8Dot3 = 0;
2708     }   
2709
2710     /* unreachable */
2711 }
2712
2713 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2714 {
2715         char umask[11];
2716         int valid;
2717         int i;
2718         char tc1;
2719         char tc2;
2720         char *tp1;
2721         char *tp2;
2722
2723         /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2724
2725         valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2726         if (!valid) 
2727                 return 0;
2728  
2729         /* otherwise, we have a valid 8.3 name; see if we have a match,
2730          * treating '?' as a wildcard in maskp (but not in the file name).
2731          */
2732         tp1 = umask;    /* real name, in mask format */
2733         tp2 = maskp;    /* mask, in mask format */
2734         for(i=0; i<11; i++) {
2735                 tc1 = *tp1++;   /* char from real name */
2736                 tc2 = *tp2++;   /* char from mask */
2737                 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2738                 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2739                 if (tc1 == tc2) 
2740                         continue;
2741                 if (tc2 == '?' && tc1 != ' ') 
2742                         continue;
2743                 if (tc2 == '>') 
2744                         continue;
2745                 return 0;
2746         }
2747
2748         /* we got a match */
2749         return 1;
2750 }
2751
2752 char *smb_FindMask(char *pathp)
2753 {
2754         char *tp;
2755         
2756         tp = strrchr(pathp, '\\');      /* find last slash */
2757
2758         if (tp) 
2759                 return tp+1;    /* skip the slash */
2760         else 
2761                 return pathp;   /* no slash, return the entire path */
2762 }
2763
2764 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2765 {
2766         unsigned char *pathp;
2767         unsigned char *tp;
2768         unsigned char mask[11];
2769         unsigned char *statBlockp;
2770         unsigned char initStatBlock[21];
2771         int statLen;
2772         
2773         osi_Log0(afsd_logp, "SMB receive search volume");
2774
2775         /* pull pathname and stat block out of request */
2776         tp = smb_GetSMBData(inp, NULL);
2777         pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2778         osi_assert(pathp != NULL);
2779         statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2780         osi_assert(statBlockp != NULL);
2781         if (statLen == 0) {
2782                 statBlockp = initStatBlock;
2783                 statBlockp[0] = 8;
2784         }
2785         
2786         /* for returning to caller */
2787         smb_Get8Dot3MaskFromPath(mask, pathp);
2788         
2789         smb_SetSMBParm(outp, 0, 1);             /* we're returning one entry */
2790         tp = smb_GetSMBData(outp, NULL);
2791         *tp++ = 5;
2792         *tp++ = 43;     /* bytes in a dir entry */
2793         *tp++ = 0;      /* high byte in counter */
2794
2795         /* now marshall the dir entry, starting with the search status */
2796         *tp++ = statBlockp[0];          /* Reserved */
2797         memcpy(tp, mask, 11); tp += 11; /* FileName */
2798
2799         /* now pass back server use info, with 1st byte non-zero */
2800         *tp++ = 1;
2801         memset(tp, 0, 4); tp += 4;      /* reserved for server use */
2802
2803         memcpy(tp, statBlockp+17, 4); tp += 4;  /* reserved for consumer */
2804
2805         *tp++ = 0x8;            /* attribute: volume */
2806
2807         /* copy out time */
2808         *tp++ = 0;
2809         *tp++ = 0;
2810
2811         /* copy out date */
2812         *tp++ = 18;
2813         *tp++ = 178;
2814
2815         /* 4 byte file size */
2816         *tp++ = 0;
2817         *tp++ = 0;
2818         *tp++ = 0;
2819         *tp++ = 0;
2820
2821         /* finally, null-terminated 8.3 pathname, which we set to AFS */
2822         memset(tp, ' ', 13);
2823         strcpy(tp, "AFS");
2824
2825         /* set the length of the data part of the packet to 43 + 3, for the dir
2826          * entry plus the 5 and the length fields.
2827          */
2828         smb_SetSMBDataLength(outp, 46);
2829         return 0;
2830 }
2831
2832 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2833         cm_user_t *userp, cm_req_t *reqp)
2834 {
2835         long code;
2836         cm_scache_t *scp;
2837         char *dptr;
2838         long dosTime;
2839         u_short shortTemp;
2840         char attr;
2841         smb_dirListPatch_t *patchp;
2842         smb_dirListPatch_t *npatchp;
2843
2844         for(patchp = *dirPatchespp; patchp; patchp =
2845                  (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2846                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2847                 if (code) continue;
2848                 lock_ObtainMutex(&scp->mx);
2849                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2850                                                   CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2851                 if (code) {     
2852                         lock_ReleaseMutex(&scp->mx);
2853                         cm_ReleaseSCache(scp);
2854                         continue;
2855                 }
2856                 dptr = patchp->dptr;
2857
2858                 attr = smb_Attributes(scp);
2859         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
2860         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2861             attr |= SMB_ATTR_HIDDEN;
2862         *dptr++ = attr;
2863
2864                 /* get dos time */
2865                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2866                 
2867                 /* copy out time */
2868                 shortTemp = dosTime & 0xffff;
2869                 *((u_short *)dptr) = shortTemp;
2870                 dptr += 2;
2871
2872                 /* and copy out date */
2873                 shortTemp = (dosTime>>16) & 0xffff;
2874                 *((u_short *)dptr) = shortTemp;
2875                 dptr += 2;
2876                 
2877                 /* copy out file length */
2878                 *((u_long *)dptr) = scp->length.LowPart;
2879                 dptr += 4;
2880                 lock_ReleaseMutex(&scp->mx);
2881                 cm_ReleaseSCache(scp);
2882         }
2883         
2884         /* now free the patches */
2885         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2886                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2887                 free(patchp);
2888         }       
2889         
2890         /* and mark the list as empty */
2891         *dirPatchespp = NULL;
2892
2893         return code;
2894 }
2895
2896 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2897 {
2898         int attribute;
2899         long nextCookie;
2900         char *tp;
2901         long code;
2902         char *pathp;
2903         cm_dirEntry_t *dep;
2904         int maxCount;
2905         smb_dirListPatch_t *dirListPatchesp;
2906         smb_dirListPatch_t *curPatchp;
2907         int dataLength;
2908         cm_buf_t *bufferp;
2909         long temp;
2910         osi_hyper_t dirLength;
2911         osi_hyper_t bufferOffset;
2912         osi_hyper_t curOffset;
2913         osi_hyper_t thyper;
2914         unsigned char *inCookiep;
2915         smb_dirSearch_t *dsp;
2916         cm_scache_t *scp;
2917         long entryInDir;
2918         long entryInBuffer;
2919         unsigned long clientCookie;
2920         cm_pageHeader_t *pageHeaderp;
2921         cm_user_t *userp = NULL;
2922         int slotInPage;
2923         char shortName[13];
2924         char *actualName;
2925         char *shortNameEnd;
2926         char mask[11];
2927         int returnedNames;
2928         long nextEntryCookie;
2929         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
2930         char resByte;                   /* reserved byte from the cookie */
2931         char *op;                       /* output data ptr */
2932         char *origOp;                   /* original value of op */
2933         cm_space_t *spacep;             /* for pathname buffer */
2934         int starPattern;
2935         int rootPath = 0;
2936         int caseFold;
2937         char *tidPathp;
2938         cm_req_t req;
2939         cm_fid_t fid;
2940         int fileType;
2941
2942         cm_InitReq(&req);
2943
2944         maxCount = smb_GetSMBParm(inp, 0);
2945
2946         dirListPatchesp = NULL;
2947         
2948         caseFold = CM_FLAG_CASEFOLD;
2949
2950         tp = smb_GetSMBData(inp, NULL);
2951         pathp = smb_ParseASCIIBlock(tp, &tp);
2952         inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
2953
2954         /* bail out if request looks bad */
2955         if (!tp || !pathp) {
2956                 return CM_ERROR_BADSMB;
2957         }
2958
2959         /* We can handle long names */
2960         if (vcp->flags & SMB_VCFLAG_USENT)
2961                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
2962
2963         /* make sure we got a whole search status */
2964         if (dataLength < 21) {
2965                 nextCookie = 0;         /* start at the beginning of the dir */
2966                 resByte = 0;
2967                 clientCookie = 0;
2968                 attribute = smb_GetSMBParm(inp, 1);
2969
2970                 /* handle volume info in another function */
2971                 if (attribute & 0x8)
2972                         return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
2973
2974                 osi_Log2(afsd_logp, "SMB receive search dir count %d [%s]",
2975                                  maxCount, osi_LogSaveString(afsd_logp, pathp));
2976
2977                 if (*pathp == 0) {      /* null pathp, treat as root dir */
2978                         if (!(attribute & SMB_ATTR_DIRECTORY))  /* exclude dirs */
2979                                 return CM_ERROR_NOFILES;
2980                         rootPath = 1;
2981                 }
2982
2983                 dsp = smb_NewDirSearch(0);
2984                 dsp->attribute = attribute;
2985                 smb_Get8Dot3MaskFromPath(mask, pathp);
2986                 memcpy(dsp->mask, mask, 11);
2987
2988                 /* track if this is likely to match a lot of entries */
2989                 if (smb_IsStarMask(mask)) starPattern = 1;
2990                 else starPattern = 0;
2991         }       
2992         else {
2993                 /* pull the next cookie value out of the search status block */
2994                 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
2995                         + (inCookiep[16]<<24);
2996                 dsp = smb_FindDirSearch(inCookiep[12]);
2997                 if (!dsp) {
2998                         /* can't find dir search status; fatal error */
2999                         return CM_ERROR_BADFD;
3000                 }
3001                 attribute = dsp->attribute;
3002                 resByte = inCookiep[0];
3003
3004                 /* copy out client cookie, in host byte order.  Don't bother
3005                  * interpreting it, since we're just passing it through, anyway.
3006                  */
3007                 memcpy(&clientCookie, &inCookiep[17], 4);
3008
3009                 memcpy(mask, dsp->mask, 11);
3010
3011                 /* assume we're doing a star match if it has continued for more
3012                  * than one call.
3013                  */
3014                 starPattern = 1;
3015         }
3016
3017         osi_Log3(afsd_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3018                          nextCookie, dsp->cookie, attribute);
3019
3020         userp = smb_GetUser(vcp, inp);
3021
3022         /* try to get the vnode for the path name next */
3023         lock_ObtainMutex(&dsp->mx);
3024         if (dsp->scp) {
3025                 scp = dsp->scp;
3026                 cm_HoldSCache(scp);
3027                 code = 0;
3028         }
3029         else {
3030                 spacep = inp->spacep;
3031                 smb_StripLastComponent(spacep->data, NULL, pathp);
3032                 lock_ReleaseMutex(&dsp->mx);
3033                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3034                 code = cm_NameI(cm_rootSCachep, spacep->data,
3035                                                 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3036                 lock_ObtainMutex(&dsp->mx);
3037                 if (code == 0) {
3038                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3039                         dsp->scp = scp;
3040                         /* we need one hold for the entry we just stored into,
3041                          * and one for our own processing.  When we're done with this
3042                          * function, we'll drop the one for our own processing.
3043                          * We held it once from the namei call, and so we do another hold
3044                          * now.
3045                          */
3046                         cm_HoldSCache(scp);
3047                         lock_ObtainMutex(&scp->mx);
3048                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3049                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3050                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3051                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3052                         }
3053                         lock_ReleaseMutex(&scp->mx);
3054                 }
3055         }
3056         lock_ReleaseMutex(&dsp->mx);
3057         if (code) {
3058                 cm_ReleaseUser(userp);
3059                 smb_DeleteDirSearch(dsp);
3060                 smb_ReleaseDirSearch(dsp);
3061                 return code;
3062         }
3063
3064         /* reserves space for parameter; we'll adjust it again later to the
3065          * real count of the # of entries we returned once we've actually
3066          * assembled the directory listing.
3067          */
3068         smb_SetSMBParm(outp, 0, 0);
3069         
3070         /* get the directory size */
3071         lock_ObtainMutex(&scp->mx);
3072         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3073                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3074         if (code) {
3075                 lock_ReleaseMutex(&scp->mx);
3076                 cm_ReleaseSCache(scp);
3077                 cm_ReleaseUser(userp);
3078                 smb_DeleteDirSearch(dsp);
3079                 smb_ReleaseDirSearch(dsp);
3080                 return code;
3081         }
3082         
3083         dirLength = scp->length;
3084         bufferp = NULL;
3085         bufferOffset.LowPart = bufferOffset.HighPart = 0;
3086         curOffset.HighPart = 0;
3087         curOffset.LowPart = nextCookie;
3088         origOp = op = smb_GetSMBData(outp, NULL);
3089         /* and write out the basic header */
3090         *op++ = 5;              /* variable block */
3091         op += 2;                /* skip vbl block length; we'll fill it in later */
3092         code = 0;
3093         returnedNames = 0;
3094         while (1) {
3095                 /* make sure that curOffset.LowPart doesn't point to the first
3096                  * 32 bytes in the 2nd through last dir page, and that it doesn't
3097                  * point at the first 13 32-byte chunks in the first dir page,
3098                  * since those are dir and page headers, and don't contain useful
3099                  * information.
3100                  */
3101                 temp = curOffset.LowPart & (2048-1);
3102                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3103                         /* we're in the first page */
3104                         if (temp < 13*32) temp = 13*32;
3105                 }
3106                 else {
3107                         /* we're in a later dir page */
3108                         if (temp < 32) temp = 32;
3109                 }
3110                 
3111                 /* make sure the low order 5 bits are zero */
3112                 temp &= ~(32-1);
3113
3114                 /* now put temp bits back ito curOffset.LowPart */
3115                 curOffset.LowPart &= ~(2048-1);
3116                 curOffset.LowPart |= temp;
3117
3118                 /* check if we've returned all the names that will fit in the
3119                  * response packet.
3120                  */
3121                 if (returnedNames >= maxCount) 
3122                         break;
3123                 
3124                 /* check if we've passed the dir's EOF */
3125                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3126
3127                 /* see if we can use the bufferp we have now; compute in which page
3128                  * the current offset would be, and check whether that's the offset
3129                  * of the buffer we have.  If not, get the buffer.
3130                  */
3131                 thyper.HighPart = curOffset.HighPart;
3132                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3133                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3134                         /* wrong buffer */
3135                         if (bufferp) {
3136                                 buf_Release(bufferp);
3137                                 bufferp = NULL;
3138                         }       
3139                         lock_ReleaseMutex(&scp->mx);
3140                         lock_ObtainRead(&scp->bufCreateLock);
3141                         code = buf_Get(scp, &thyper, &bufferp);
3142                         lock_ReleaseRead(&scp->bufCreateLock);
3143
3144                         /* now, if we're doing a star match, do bulk fetching of all of 
3145                          * the status info for files in the dir.
3146                          */
3147                         if (starPattern) {
3148                                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3149                                                                                 &req);
3150                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3151                                     && LargeIntegerGreaterThanOrEqualTo(thyper, 
3152                                                                         scp->bulkStatProgress)) {
3153                                         /* Don't bulk stat if risking timeout */
3154                                         int now = GetCurrentTime();
3155                                         if (now - req.startTime > 5000) {
3156                                                 scp->bulkStatProgress = thyper;
3157                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3158                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3159                                         } else
3160                                                 cm_TryBulkStat(scp, &thyper, userp, &req);
3161                                 }
3162                         }
3163
3164                         lock_ObtainMutex(&scp->mx);
3165                         if (code) 
3166                                 break;
3167                         bufferOffset = thyper;
3168
3169                         /* now get the data in the cache */
3170                         while (1) {
3171                                 code = cm_SyncOp(scp, bufferp, userp, &req,
3172                                                                   PRSFS_LOOKUP,
3173                                                                   CM_SCACHESYNC_NEEDCALLBACK
3174                                                                   | CM_SCACHESYNC_READ);
3175                                 if (code) break;
3176                                 
3177                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3178
3179                                 /* otherwise, load the buffer and try again */
3180                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3181                                                                         &req);
3182                                 if (code) break;
3183                         }
3184                         if (code) {
3185                                 buf_Release(bufferp);
3186                                 bufferp = NULL;
3187                                 break;
3188                         }
3189                 }       /* if (wrong buffer) ... */
3190
3191                 /* now we have the buffer containing the entry we're interested in; copy
3192                  * it out if it represents a non-deleted entry.
3193                  */
3194                 entryInDir = curOffset.LowPart & (2048-1);
3195                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3196
3197                 /* page header will help tell us which entries are free.  Page header
3198                  * can change more often than once per buffer, since AFS 3 dir page size
3199                  * may be less than (but not more than a buffer package buffer.
3200                  */
3201                 temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
3202                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
3203                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3204
3205                 /* now determine which entry we're looking at in the page.  If it is
3206                  * free (there's a free bitmap at the start of the dir), we should
3207                  * skip these 32 bytes.
3208                  */
3209                 slotInPage = (entryInDir & 0x7e0) >> 5;
3210                 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3211                         /* this entry is free */
3212                         numDirChunks = 1;               /* only skip this guy */
3213                         goto nextEntry;
3214                 }
3215
3216                 tp = bufferp->datap + entryInBuffer;
3217                 dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3218
3219                 /* while we're here, compute the next entry's location, too,
3220                  * since we'll need it when writing out the cookie into the dir
3221                  * listing stream.
3222                  *
3223                  * XXXX Probably should do more sanity checking.
3224                  */
3225                 numDirChunks = cm_NameEntries(dep->name, NULL);
3226                 
3227                 /* compute the offset of the cookie representing the next entry */
3228                 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3229
3230                 /* Compute 8.3 name if necessary */
3231                 actualName = dep->name;
3232                 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3233                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3234                         actualName = shortName;
3235                 }
3236
3237                 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3238                         /* this is one of the entries to use: it is not deleted
3239                          * and it matches the star pattern we're looking for.
3240                          */
3241
3242                         /* Eliminate entries that don't match requested
3243                            attributes */
3244
3245                         /* no hidden files */
3246                         if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3247                                 goto nextEntry;
3248
3249                         if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3250                         {
3251                                 /* We have already done the cm_TryBulkStat above */
3252                                 fid.cell = scp->fid.cell;
3253                                 fid.volume = scp->fid.volume;
3254                                 fid.vnode = ntohl(dep->fid.vnode);
3255                                 fid.unique = ntohl(dep->fid.unique);
3256                                 fileType = cm_FindFileType(&fid);
3257                                 osi_Log2(afsd_logp, "smb_ReceiveCoreSearchDir: file %s "
3258                                                   "has filetype %d", dep->name,
3259                                                   fileType);
3260                                 if (fileType == CM_SCACHETYPE_DIRECTORY)
3261                                         goto nextEntry;
3262                         }
3263
3264                         *op++ = resByte;
3265                         memcpy(op, mask, 11); op += 11;
3266                         *op++ = (char) dsp->cookie;     /* they say it must be non-zero */
3267                         *op++ = nextEntryCookie & 0xff;
3268                         *op++ = (nextEntryCookie>>8) & 0xff;
3269                         *op++ = (nextEntryCookie>>16) & 0xff;
3270                         *op++ = (nextEntryCookie>>24) & 0xff;
3271                         memcpy(op, &clientCookie, 4); op += 4;
3272
3273                         /* now we emit the attribute.  This is sort of tricky,
3274                          * since we need to really stat the file to find out
3275                          * what type of entry we've got.  Right now, we're
3276                          * copying out data from a buffer, while holding the
3277                          * scp locked, so it isn't really convenient to stat
3278                          * something now.  We'll put in a place holder now,
3279                          * and make a second pass before returning this to get
3280                          * the real attributes.  So, we just skip the data for
3281                          * now, and adjust it later.  We allocate a patch
3282                          * record to make it easy to find this point later.
3283                          * The replay will happen at a time when it is safe to
3284                          * unlock the directory.
3285                          */
3286                         curPatchp = malloc(sizeof(*curPatchp));
3287                         osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3288                         curPatchp->dptr = op;
3289                         curPatchp->fid.cell = scp->fid.cell;
3290                         curPatchp->fid.volume = scp->fid.volume;
3291                         curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3292                         curPatchp->fid.unique = ntohl(dep->fid.unique);
3293
3294                         /* do hidden attribute here since name won't be around when applying
3295                          * dir list patches
3296                          */
3297
3298                         if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3299                                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3300                         else
3301                                 curPatchp->flags = 0;
3302
3303                         op += 9;        /* skip attr, time, date and size */
3304
3305                         /* zero out name area.  The spec says to pad with
3306                          * spaces, but Samba doesn't, and neither do we.
3307                          */
3308                         memset(op, 0, 13);
3309
3310                         /* finally, we get to copy out the name; we know that
3311                          * it fits in 8.3 or the pattern wouldn't match, but it
3312                          * never hurts to be sure.
3313                          */
3314                         strncpy(op, actualName, 13);
3315
3316                         /* Uppercase if requested by client */
3317                         if ((((smb_t *)inp)->flg2 & 1) == 0)
3318                                 _strupr(op);
3319
3320                         op += 13;
3321
3322                         /* now, adjust the # of entries copied */
3323                         returnedNames++;
3324                 }       /* if we're including this name */
3325                 
3326           nextEntry:
3327                 /* and adjust curOffset to be where the new cookie is */
3328                 thyper.HighPart = 0;
3329                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3330                 curOffset = LargeIntegerAdd(thyper, curOffset);
3331         }               /* while copying data for dir listing */
3332
3333         /* release the mutex */
3334         lock_ReleaseMutex(&scp->mx);
3335         if (bufferp) buf_Release(bufferp);
3336
3337         /* apply and free last set of patches; if not doing a star match, this
3338          * will be empty, but better safe (and freeing everything) than sorry.
3339          */
3340         smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3341
3342         /* special return code for unsuccessful search */
3343         if (code == 0 && dataLength < 21 && returnedNames == 0)
3344                 code = CM_ERROR_NOFILES;
3345
3346         osi_Log2(afsd_logp, "SMB search dir done, %d names, code %d",
3347                  returnedNames, code);
3348
3349         if (code != 0) {
3350                 smb_DeleteDirSearch(dsp);
3351                 smb_ReleaseDirSearch(dsp);
3352                 cm_ReleaseSCache(scp);
3353                 cm_ReleaseUser(userp);
3354                 return code;
3355         }
3356
3357         /* finalize the output buffer */
3358         smb_SetSMBParm(outp, 0, returnedNames);
3359         temp = (long) (op - origOp);
3360         smb_SetSMBDataLength(outp, temp);
3361
3362         /* the data area is a variable block, which has a 5 (already there)
3363          * followed by the length of the # of data bytes.  We now know this to
3364          * be "temp," although that includes the 3 bytes of vbl block header.
3365          * Deduct for them and fill in the length field.
3366          */
3367         temp -= 3;              /* deduct vbl block info */
3368         osi_assert(temp == (43 * returnedNames));
3369         origOp[1] = temp & 0xff;
3370         origOp[2] = (temp>>8) & 0xff;
3371         if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3372         smb_ReleaseDirSearch(dsp);
3373         cm_ReleaseSCache(scp);
3374         cm_ReleaseUser(userp);
3375         return code;
3376 }       
3377
3378 /* verify that this is a valid path to a directory.  I don't know why they
3379  * don't use the get file attributes call.
3380  */
3381 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3382 {
3383         char *pathp;
3384         long code;
3385         cm_scache_t *rootScp;
3386         cm_scache_t *newScp;
3387         cm_user_t *userp;
3388         unsigned int attrs;
3389         int caseFold;
3390         char *tidPathp;
3391         cm_req_t req;
3392
3393         cm_InitReq(&req);
3394
3395         pathp = smb_GetSMBData(inp, NULL);
3396         pathp = smb_ParseASCIIBlock(pathp, NULL);
3397         osi_Log1(afsd_logp, "SMB receive check path %s",
3398                           osi_LogSaveString(afsd_logp, pathp));
3399
3400         if (!pathp) {
3401                 return CM_ERROR_BADFD;
3402         }
3403         
3404         rootScp = cm_rootSCachep;
3405         
3406         userp = smb_GetUser(vcp, inp);
3407
3408         caseFold = CM_FLAG_CASEFOLD;
3409
3410         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3411         code = cm_NameI(rootScp, pathp,
3412                                          caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3413                                          userp, tidPathp, &req, &newScp);
3414
3415         if (code) {
3416                 cm_ReleaseUser(userp);
3417                 return code;
3418         }
3419         
3420         /* now lock the vnode with a callback; returns with newScp locked */
3421         lock_ObtainMutex(&newScp->mx);
3422         code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3423                                           CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3424         if (code && code != CM_ERROR_NOACCESS) {
3425                 lock_ReleaseMutex(&newScp->mx);
3426                 cm_ReleaseSCache(newScp);
3427                 cm_ReleaseUser(userp);
3428                 return code;
3429         }
3430
3431         attrs = smb_Attributes(newScp);
3432
3433         if (!(attrs & 0x10))
3434                 code = CM_ERROR_NOTDIR;
3435
3436         lock_ReleaseMutex(&newScp->mx);
3437
3438         cm_ReleaseSCache(newScp);
3439         cm_ReleaseUser(userp);
3440         return code;
3441 }       
3442
3443 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3444 {
3445         char *pathp;
3446         long code;
3447         cm_scache_t *rootScp;
3448         unsigned short attribute;
3449         cm_attr_t attr;
3450         cm_scache_t *newScp;
3451         long dosTime;
3452         cm_user_t *userp;
3453         int caseFold;
3454         char *tidPathp;
3455         cm_req_t req;
3456
3457         cm_InitReq(&req);
3458
3459         /* decode basic attributes we're passed */
3460         attribute = smb_GetSMBParm(inp, 0);
3461         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3462
3463         pathp = smb_GetSMBData(inp, NULL);
3464         pathp = smb_ParseASCIIBlock(pathp, NULL);
3465         
3466         if (!pathp) {
3467                 return CM_ERROR_BADSMB;
3468         }
3469         
3470         osi_Log2(afsd_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3471                          dosTime, attribute);
3472
3473         rootScp = cm_rootSCachep;
3474         
3475         userp = smb_GetUser(vcp, inp);
3476
3477         caseFold = CM_FLAG_CASEFOLD;
3478
3479         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3480         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3481                                         tidPathp, &req, &newScp);
3482
3483         if (code) {
3484                 cm_ReleaseUser(userp);
3485                 return code;
3486         }
3487         
3488         /* now lock the vnode with a callback; returns with newScp locked; we
3489          * need the current status to determine what the new status is, in some
3490          * cases.
3491          */
3492         lock_ObtainMutex(&newScp->mx);
3493         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3494                                          CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3495         if (code) {
3496                 lock_ReleaseMutex(&newScp->mx);
3497                 cm_ReleaseSCache(newScp);
3498                 cm_ReleaseUser(userp);
3499                 return code;
3500         }
3501
3502         /* Check for RO volume */
3503         if (newScp->flags & CM_SCACHEFLAG_RO) {
3504                 lock_ReleaseMutex(&newScp->mx);
3505                 cm_ReleaseSCache(newScp);
3506                 cm_ReleaseUser(userp);
3507                 return CM_ERROR_READONLY;
3508         }
3509
3510         /* prepare for setattr call */
3511         attr.mask = 0;
3512         if (dosTime != 0) {
3513                 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3514                 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3515         }
3516         if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3517                 /* we're told to make a writable file read-only */
3518                 attr.unixModeBits = newScp->unixModeBits & ~0222;
3519                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3520         }
3521         else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3522                 /* we're told to make a read-only file writable */
3523                 attr.unixModeBits = newScp->unixModeBits | 0222;
3524                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3525         }
3526         lock_ReleaseMutex(&newScp->mx);
3527
3528         /* now call setattr */
3529         if (attr.mask)
3530                 code = cm_SetAttr(newScp, &attr, userp, &req);
3531         else
3532                 code = 0;
3533         
3534         cm_ReleaseSCache(newScp);
3535         cm_ReleaseUser(userp);
3536
3537         return code;
3538 }
3539
3540 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3541 {
3542         char *pathp;
3543         long code;
3544         cm_scache_t *rootScp;
3545         cm_scache_t *newScp, *dscp;
3546         long dosTime;
3547         int attrs;
3548         cm_user_t *userp;
3549         int caseFold;
3550         char *tidPathp;
3551         cm_space_t *spacep;
3552         char *lastComp;
3553         cm_req_t req;
3554
3555         cm_InitReq(&req);
3556
3557         pathp = smb_GetSMBData(inp, NULL);
3558         pathp = smb_ParseASCIIBlock(pathp, NULL);
3559         
3560         if (!pathp) {
3561                 return CM_ERROR_BADSMB;
3562         }
3563         
3564         if (*pathp == 0)                /* null path */
3565                 pathp = "\\";
3566
3567         osi_Log1(afsd_logp, "SMB receive getfile attributes path %s",
3568                          osi_LogSaveString(afsd_logp, pathp));
3569
3570         rootScp = cm_rootSCachep;
3571         
3572         userp = smb_GetUser(vcp, inp);
3573
3574         /* we shouldn't need this for V3 requests, but we seem to */
3575         caseFold = CM_FLAG_CASEFOLD;
3576
3577         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3578
3579         /*
3580          * XXX Strange hack XXX
3581          *
3582          * As of Patch 5 (16 July 97), we are having the following problem:
3583          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3584          * requests to look up "desktop.ini" in all the subdirectories.
3585          * This can cause zillions of timeouts looking up non-existent cells
3586          * and volumes, especially in the top-level directory.
3587          *
3588          * We have not found any way to avoid this or work around it except
3589          * to explicitly ignore the requests for mount points that haven't
3590          * yet been evaluated and for directories that haven't yet been
3591          * fetched.
3592          *
3593          * We should modify this hack to provide a fake desktop.ini file
3594          * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3595          */
3596         spacep = inp->spacep;
3597         smb_StripLastComponent(spacep->data, &lastComp, pathp);
3598         if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3599                 code = cm_NameI(rootScp, spacep->data,
3600                                                 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3601                                                 userp, tidPathp, &req, &dscp);
3602                 if (code == 0) {
3603                         if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3604                             && !dscp->mountRootFidp)
3605                                 code = CM_ERROR_NOSUCHFILE;
3606                         else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3607                                 cm_buf_t *bp = buf_Find(dscp, &hzero);
3608                                 if (bp)
3609                                         buf_Release(bp);
3610                                 else
3611                                         code = CM_ERROR_NOSUCHFILE;
3612                         }
3613                         cm_ReleaseSCache(dscp);
3614                         if (code) {
3615                                 cm_ReleaseUser(userp);
3616                                 return code;
3617                         }
3618                 }
3619         }
3620
3621         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3622                                         tidPathp, &req, &newScp);
3623
3624         if (code) {
3625                 cm_ReleaseUser(userp);
3626                 return code;
3627         }
3628         
3629         /* now lock the vnode with a callback; returns with newScp locked */
3630         lock_ObtainMutex(&newScp->mx);
3631         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3632                                          CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3633         if (code) {
3634                 lock_ReleaseMutex(&newScp->mx);
3635                 cm_ReleaseSCache(newScp);
3636                 cm_ReleaseUser(userp);
3637                 return code;
3638         }
3639
3640 #ifdef undef
3641     /* use smb_Attributes instead.   Also the fact that a file is 
3642          * in a readonly volume doesn't mean it shojuld be marked as RO 
3643          */
3644         if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3645                 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3646                 attrs = SMB_ATTR_DIRECTORY;
3647         else
3648                 attrs = 0;
3649         if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
3650                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
3651 #else
3652     attrs = smb_Attributes(newScp);
3653 #endif
3654
3655         smb_SetSMBParm(outp, 0, attrs);
3656         
3657         smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
3658         smb_SetSMBParm(outp, 1, dosTime & 0xffff);
3659         smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
3660         smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
3661         smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
3662         smb_SetSMBParm(outp, 5, 0);
3663         smb_SetSMBParm(outp, 6, 0);
3664         smb_SetSMBParm(outp, 7, 0);
3665         smb_SetSMBParm(outp, 8, 0);
3666         smb_SetSMBParm(outp, 9, 0);
3667         smb_SetSMBDataLength(outp, 0);
3668         lock_ReleaseMutex(&newScp->mx);
3669
3670         cm_ReleaseSCache(newScp);
3671         cm_ReleaseUser(userp);
3672         
3673         return 0;
3674 }       
3675
3676 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3677 {
3678         smb_tid_t *tidp;
3679         
3680         osi_Log0(afsd_logp, "SMB receive tree disconnect");
3681
3682         /* find the tree and free it */
3683         tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
3684         if (tidp) {
3685                 lock_ObtainMutex(&tidp->mx);
3686                 tidp->flags |= SMB_TIDFLAG_DELETE;
3687                 lock_ReleaseMutex(&tidp->mx);
3688                 smb_ReleaseTID(tidp);
3689         }
3690
3691         return 0;
3692 }
3693
3694 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3695 {
3696         smb_fid_t *fidp;
3697     char *pathp;
3698         char *lastNamep;
3699     int share;
3700     int attribute;
3701         long code;
3702     cm_user_t *userp;
3703     cm_scache_t *scp;
3704     long dosTime;
3705     int caseFold;
3706         cm_space_t *spacep;
3707         char *tidPathp;
3708         cm_req_t req;
3709
3710         cm_InitReq(&req);
3711
3712     pathp = smb_GetSMBData(inp, NULL);
3713     pathp = smb_ParseASCIIBlock(pathp, NULL);
3714         
3715     osi_Log1(afsd_logp, "SMB receive open file [%s]", osi_LogSaveString(afsd_logp, pathp));
3716
3717 #ifdef DEBUG_VERBOSE
3718     {
3719         char *hexpath;
3720
3721         hexpath = osi_HexifyString( pathp );
3722         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
3723         free(hexpath);
3724     }
3725 #endif
3726
3727         share = smb_GetSMBParm(inp, 0);
3728     attribute = smb_GetSMBParm(inp, 1);
3729
3730         spacep = inp->spacep;
3731         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3732         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3733                 /* special case magic file name for receiving IOCTL requests
3734          * (since IOCTL calls themselves aren't getting through).
3735          */
3736         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3737                 smb_SetupIoctlFid(fidp, spacep);
3738                 smb_SetSMBParm(outp, 0, fidp->fid);
3739         smb_SetSMBParm(outp, 1, 0);     /* attrs */
3740         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
3741         smb_SetSMBParm(outp, 3, 0);
3742         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
3743         smb_SetSMBParm(outp, 5, 0x7fff);
3744                 /* pass the open mode back */
3745         smb_SetSMBParm(outp, 6, (share & 0xf));
3746         smb_SetSMBDataLength(outp, 0);
3747         smb_ReleaseFID(fidp);
3748         return 0;
3749     }
3750
3751         userp = smb_GetUser(vcp, inp);
3752
3753         caseFold = CM_FLAG_CASEFOLD;
3754
3755         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3756     code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3757                     tidPathp, &req, &scp);
3758         
3759     if (code) {
3760         cm_ReleaseUser(userp);
3761                 return code;
3762         }
3763         
3764     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
3765         if (code) {
3766                 cm_ReleaseSCache(scp);
3767                 cm_ReleaseUser(userp);
3768                 return code;
3769         }
3770
3771         /* don't need callback to check file type, since file types never
3772          * change, and namei and cm_Lookup all stat the object at least once on
3773          * a successful return.
3774      */
3775     if (scp->fileType != CM_SCACHETYPE_FILE) {
3776                 cm_ReleaseSCache(scp);
3777         cm_ReleaseUser(userp);
3778         return CM_ERROR_ISDIR;
3779     }
3780
3781     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3782     osi_assert(fidp);
3783
3784         /* save a pointer to the vnode */
3785     fidp->scp = scp;
3786
3787     if ((share & 0xf) == 0)
3788         fidp->flags |= SMB_FID_OPENREAD;
3789         else if ((share & 0xf) == 1)
3790         fidp->flags |= SMB_FID_OPENWRITE;
3791         else 
3792         fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
3793
3794         lock_ObtainMutex(&scp->mx);
3795         smb_SetSMBParm(outp, 0, fidp->fid);
3796     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
3797         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3798     smb_SetSMBParm(outp, 2, dosTime & 0xffff);
3799     smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
3800     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
3801     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
3802         /* pass the open mode back; XXXX add access checks */
3803     smb_SetSMBParm(outp, 6, (share & 0xf));
3804     smb_SetSMBDataLength(outp, 0);
3805         lock_ReleaseMutex(&scp->mx);
3806         
3807         /* notify open */
3808     cm_Open(scp, 0, userp);
3809
3810         /* send and free packet */
3811     smb_ReleaseFID(fidp);
3812     cm_ReleaseUser(userp);
3813     /* don't release scp, since we've squirreled away the pointer in the fid struct */
3814     return 0;
3815 }
3816
3817 typedef struct smb_unlinkRock {
3818         cm_scache_t *dscp;
3819         cm_user_t *userp;
3820         cm_req_t *reqp;
3821         smb_vc_t *vcp;
3822         char *maskp;            /* pointer to the star pattern */
3823         int hasTilde;
3824         int any;
3825 } smb_unlinkRock_t;
3826
3827 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3828 {
3829         long code;
3830         smb_unlinkRock_t *rockp;
3831         int caseFold;
3832         int match;
3833         char shortName[13];
3834         char *matchName;
3835         
3836         rockp = vrockp;
3837
3838         if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3839                 caseFold = CM_FLAG_CASEFOLD;
3840         else 
3841                 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3842
3843         matchName = dep->name;
3844         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3845         if (!match
3846             && rockp->hasTilde
3847             && !cm_Is8Dot3(dep->name)) {
3848                 cm_Gen8Dot3Name(dep, shortName, NULL);
3849                 matchName = shortName;
3850                 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3851         }
3852         if (match) {
3853                 osi_Log1(smb_logp, "Unlinking %s",
3854                                  osi_LogSaveString(smb_logp, matchName));
3855                 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
3856                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3857                         smb_NotifyChange(FILE_ACTION_REMOVED,
3858                                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3859                                                          dscp, dep->name, NULL, TRUE);
3860                 if (code == 0)
3861                         rockp->any = 1;
3862         }
3863         else code = 0;
3864
3865         return code;
3866 }
3867
3868 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3869 {
3870         int attribute;
3871         long code;
3872         char *pathp;
3873         char *tp;
3874         cm_space_t *spacep;
3875         cm_scache_t *dscp;
3876         char *lastNamep;
3877         smb_unlinkRock_t rock;
3878         cm_user_t *userp;
3879         osi_hyper_t thyper;
3880         int caseFold;
3881         char *tidPathp;
3882         cm_req_t req;
3883
3884         cm_InitReq(&req);
3885
3886         attribute = smb_GetSMBParm(inp, 0);
3887         
3888         tp = smb_GetSMBData(inp, NULL);
3889         pathp = smb_ParseASCIIBlock(tp, &tp);
3890
3891         osi_Log1(smb_logp, "SMB receive unlink %s",
3892                          osi_LogSaveString(smb_logp, pathp));
3893
3894         spacep = inp->spacep;
3895         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3896
3897         userp = smb_GetUser(vcp, inp);
3898
3899         caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3900
3901         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3902         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
3903                                         &req, &dscp);
3904
3905         if (code) {
3906                 cm_ReleaseUser(userp);
3907                 return code;
3908         }
3909         
3910         /* otherwise, scp points to the parent directory. */
3911         if (!lastNamep) 
3912                 lastNamep = pathp;
3913         else 
3914                 lastNamep++;
3915
3916         rock.any = 0;
3917         rock.maskp = smb_FindMask(pathp);
3918         rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
3919         
3920         thyper.LowPart = 0;
3921         thyper.HighPart = 0;
3922         rock.userp = userp;
3923         rock.reqp = &req;
3924         rock.dscp = dscp;
3925         rock.vcp = vcp;
3926         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
3927
3928         cm_ReleaseUser(userp);
3929         
3930         cm_ReleaseSCache(dscp);
3931
3932         if (code == 0 && !rock.any)
3933                 code = CM_ERROR_NOSUCHFILE;
3934         return code;
3935 }
3936
3937 typedef struct smb_renameRock {
3938         cm_scache_t *odscp;     /* old dir */
3939         cm_scache_t *ndscp;     /* new dir */
3940         cm_user_t *userp;       /* user */
3941         cm_req_t *reqp;         /* request struct */
3942         smb_vc_t *vcp;          /* virtual circuit */
3943         char *maskp;            /* pointer to star pattern of old file name */
3944         int hasTilde;           /* star pattern might be shortname? */
3945         char *newNamep;         /* ptr to the new file's name */
3946 } smb_renameRock_t;
3947
3948 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3949 {
3950         long code;
3951         smb_renameRock_t *rockp;
3952         int caseFold;
3953         int match;
3954         char shortName[13];
3955         
3956         rockp = vrockp;
3957
3958         if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3959                 caseFold = CM_FLAG_CASEFOLD;
3960         else 
3961                 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3962
3963         match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
3964         if (!match
3965             && rockp->hasTilde
3966             && !cm_Is8Dot3(dep->name)) {
3967                 cm_Gen8Dot3Name(dep, shortName, NULL);
3968                 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
3969         }
3970         if (match) {
3971                 code = cm_Rename(rockp->odscp, dep->name,
3972                                                  rockp->ndscp, rockp->newNamep, rockp->userp,
3973                                                  rockp->reqp);  
3974                 /* if the call worked, stop doing the search now, since we
3975                  * really only want to rename one file.
3976                  */
3977                 if (code == 0) 
3978                         code = CM_ERROR_STOPNOW;
3979         }
3980         else code = 0;
3981
3982         return code;
3983 }
3984
3985 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3986 {
3987         long code;
3988         char *oldPathp;
3989         char *newPathp;
3990         char *tp;
3991         cm_space_t *spacep;
3992         smb_renameRock_t rock;
3993         cm_scache_t *oldDscp;
3994         cm_scache_t *newDscp;
3995         cm_scache_t *tmpscp;
3996         char *oldLastNamep;
3997         char *newLastNamep;
3998         osi_hyper_t thyper;
3999         cm_user_t *userp;
4000         int caseFold;
4001         char *tidPathp;
4002         DWORD filter;
4003         cm_req_t req;
4004
4005         cm_InitReq(&req);
4006         
4007         tp = smb_GetSMBData(inp, NULL);
4008         oldPathp = smb_ParseASCIIBlock(tp, &tp);
4009         newPathp = smb_ParseASCIIBlock(tp, &tp);
4010
4011         osi_Log2(afsd_logp, "smb rename %s to %s",
4012                          osi_LogSaveString(afsd_logp, oldPathp),
4013                          osi_LogSaveString(afsd_logp, newPathp));
4014
4015         spacep = inp->spacep;
4016         smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4017
4018         userp = smb_GetUser(vcp, inp);
4019
4020  /*
4021   * Changed to use CASEFOLD always.  This enables us to rename Foo/baz when
4022   * what actually exists is foo/baz.  I don't know why the code used to be
4023   * the way it was.  1/29/96
4024   *
4025   *             caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4026   *
4027   * Changed to use CM_FLAG_FOLLOW.  7/24/96
4028   *
4029   *     caseFold = CM_FLAG_CASEFOLD;
4030   */
4031         caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4032
4033         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4034         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4035                                         userp, tidPathp, &req, &oldDscp);
4036
4037         if (code) {
4038                 cm_ReleaseUser(userp);
4039                 return code;
4040         }
4041         
4042         smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4043         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4044                                         userp, tidPathp, &req, &newDscp);
4045
4046         if (code) {
4047                 cm_ReleaseSCache(oldDscp);
4048                 cm_ReleaseUser(userp);
4049                 return code;
4050         }
4051         
4052         /* otherwise, oldDscp and newDscp point to the corresponding directories.
4053          * next, get the component names, and lower case them.
4054          */
4055
4056         /* handle the old name first */
4057         if (!oldLastNamep) 
4058                 oldLastNamep = oldPathp;
4059         else 
4060                 oldLastNamep++;
4061
4062         /* and handle the new name, too */
4063         if (!newLastNamep) 
4064                 newLastNamep = newPathp;
4065         else 
4066                 newLastNamep++;
4067         
4068         /* do the vnode call */
4069         rock.odscp = oldDscp;
4070         rock.ndscp = newDscp;
4071         rock.userp = userp;
4072         rock.reqp = &req;
4073         rock.vcp = vcp;
4074         rock.maskp = oldLastNamep;
4075         rock.hasTilde = ((strchr(oldLastNamep, '~') != NULL) ? 1 : 0);
4076         rock.newNamep = newLastNamep;
4077
4078     /* Check if the file already exists; if so return error */
4079         code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4080         if((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4081             cm_ReleaseSCache(tmpscp);
4082             return CM_ERROR_EXISTS; /* file exist, do not rename, also 
4083                                          * fixes move
4084                                                                  */
4085         }
4086
4087     /* Now search the directory for the pattern, and do the appropriate rename when found */
4088         thyper.LowPart = 0;             /* search dir from here */
4089     thyper.HighPart = 0;
4090
4091     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4092
4093     if (code == CM_ERROR_STOPNOW)
4094                 code = 0;
4095         else if (code == 0)
4096                 code = CM_ERROR_NOSUCHFILE;
4097
4098         /* Handle Change Notification */
4099         /*
4100          * Being lazy, not distinguishing between files and dirs in this
4101          * filter, since we'd have to do a lookup.
4102          */
4103         filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4104         if (oldDscp == newDscp) {
4105                 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4106                         smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4107                                                          filter, oldDscp, oldLastNamep,
4108                                                          newLastNamep, TRUE);
4109         } else {
4110                 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4111                         smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4112                                                          filter, oldDscp, oldLastNamep,
4113                                                          NULL, TRUE);
4114                 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4115                         smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4116                                                          filter, newDscp, newLastNamep,
4117                                                          NULL, TRUE);
4118         }
4119
4120         cm_ReleaseUser(userp);
4121         
4122         cm_ReleaseSCache(oldDscp);
4123         cm_ReleaseSCache(newDscp);
4124
4125         return code;
4126 }
4127
4128 typedef struct smb_rmdirRock {
4129         cm_scache_t *dscp;
4130         cm_user_t *userp;
4131         cm_req_t *reqp;
4132         char *maskp;            /* pointer to the star pattern */
4133         int hasTilde;
4134         int any;
4135 } smb_rmdirRock_t;
4136
4137 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4138 {
4139         long code;
4140         smb_rmdirRock_t *rockp;
4141         int match;
4142         char shortName[13];
4143         char *matchName;
4144         
4145         rockp = vrockp;
4146
4147         matchName = dep->name;
4148         match = (cm_stricmp(matchName, rockp->maskp) == 0);
4149         if (!match
4150             && rockp->hasTilde
4151             && !cm_Is8Dot3(dep->name)) {
4152                 cm_Gen8Dot3Name(dep, shortName, NULL);
4153                 matchName = shortName;
4154                 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4155         }
4156         if (match) {
4157                 osi_Log1(smb_logp, "Removing directory %s",
4158                                  osi_LogSaveString(smb_logp, matchName));
4159                 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4160                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4161                         smb_NotifyChange(FILE_ACTION_REMOVED,
4162                                                          FILE_NOTIFY_CHANGE_DIR_NAME,
4163                                                          dscp, dep->name, NULL, TRUE);
4164                 if (code == 0)
4165                         rockp->any = 1;
4166         }
4167         else code = 0;
4168
4169         return code;
4170 }
4171
4172 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4173 {
4174         long code;
4175         char *pathp;
4176         char *tp;
4177         cm_space_t *spacep;
4178         cm_scache_t *dscp;
4179         char *lastNamep;
4180         smb_rmdirRock_t rock;
4181         cm_user_t *userp;
4182         osi_hyper_t thyper;
4183         int caseFold;
4184         char *tidPathp;
4185         cm_req_t req;
4186
4187         cm_InitReq(&req);
4188
4189         tp = smb_GetSMBData(inp, NULL);
4190         pathp = smb_ParseASCIIBlock(tp, &tp);
4191
4192         spacep = inp->spacep;
4193         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4194
4195         userp = smb_GetUser(vcp, inp);
4196
4197         caseFold = CM_FLAG_CASEFOLD;
4198
4199         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4200         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4201                                         userp, tidPathp, &req, &dscp);
4202
4203         if (code) {
4204                 cm_ReleaseUser(userp);
4205                 return code;
4206         }
4207         
4208         /* otherwise, scp points to the parent directory. */
4209         if (!lastNamep) 
4210                 lastNamep = pathp;
4211         else 
4212                 lastNamep++;
4213         
4214         rock.any = 0;
4215         rock.maskp = lastNamep;
4216         rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
4217
4218         thyper.LowPart = 0;
4219         thyper.HighPart = 0;
4220         rock.userp = userp;
4221         rock.reqp = &req;
4222         rock.dscp = dscp;
4223         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4224
4225         cm_ReleaseUser(userp);
4226         
4227         cm_ReleaseSCache(dscp);
4228
4229         if (code == 0 && !rock.any)
4230                 code = CM_ERROR_NOSUCHFILE;        
4231         return code;
4232 }
4233
4234 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4235 {
4236         unsigned short fid;
4237     smb_fid_t *fidp;
4238     cm_user_t *userp;
4239     long code;
4240     cm_req_t req;
4241
4242         cm_InitReq(&req);
4243
4244         fid = smb_GetSMBParm(inp, 0);
4245         
4246         osi_Log1(afsd_logp, "SMB flush fid %d", fid);
4247
4248         fid = smb_ChainFID(fid, inp);
4249     fidp = smb_FindFID(vcp, fid, 0);
4250     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4251         if (fidp)
4252             smb_ReleaseFID(fidp);
4253         return CM_ERROR_BADFD;
4254     }
4255         
4256     userp = smb_GetUser(vcp, inp);
4257
4258     lock_ObtainMutex(&fidp->mx);
4259     if (fidp->flags & SMB_FID_OPENWRITE)
4260         code = cm_FSync(fidp->scp, userp, &req);
4261         else 
4262                 code = 0;
4263     lock_ReleaseMutex(&fidp->mx);
4264         
4265     smb_ReleaseFID(fidp);
4266         
4267     cm_ReleaseUser(userp);
4268         
4269     return code;
4270 }
4271
4272 struct smb_FullNameRock {
4273         char *name;
4274         cm_scache_t *vnode;
4275         char *fullName;
4276 };
4277
4278 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4279         osi_hyper_t *offp)
4280 {
4281         char shortName[13];
4282         struct smb_FullNameRock *vrockp;
4283
4284         vrockp = rockp;
4285
4286         if (!cm_Is8Dot3(dep->name)) {
4287                 cm_Gen8Dot3Name(dep, shortName, NULL);
4288
4289                 if (strcmp(shortName, vrockp->name) == 0) {
4290                         vrockp->fullName = strdup(dep->name);
4291                         return CM_ERROR_STOPNOW;
4292                 }
4293         }
4294         if (stricmp(dep->name, vrockp->name) == 0
4295             && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4296             && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4297                 vrockp->fullName = strdup(dep->name);
4298                 return CM_ERROR_STOPNOW;
4299         }
4300         return 0;
4301 }
4302
4303 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4304         char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4305 {
4306         struct smb_FullNameRock rock;
4307         long code;
4308
4309         rock.name = pathp;
4310         rock.vnode = scp;
4311
4312         code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, 
4313                                 userp, reqp, NULL); 
4314         if (code == CM_ERROR_STOPNOW)
4315                 *newPathp = rock.fullName;
4316         else
4317                 *newPathp = strdup(pathp);
4318 }
4319
4320 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4321 {
4322         unsigned short fid;
4323     smb_fid_t *fidp;
4324     cm_user_t *userp;
4325         long dosTime;
4326     long code;
4327         cm_req_t req;
4328
4329         cm_InitReq(&req);
4330
4331         fid = smb_GetSMBParm(inp, 0);
4332         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4333         
4334         osi_Log1(afsd_logp, "SMB close fid %d", fid);
4335
4336         fid = smb_ChainFID(fid, inp);
4337     fidp = smb_FindFID(vcp, fid, 0);
4338     if (!fidp) {
4339         return CM_ERROR_BADFD;
4340     }
4341         
4342         userp = smb_GetUser(vcp, inp);
4343
4344     lock_ObtainMutex(&fidp->mx);
4345
4346         /* Don't jump the gun on an async raw write */
4347         while (fidp->raw_writers) {
4348                 lock_ReleaseMutex(&fidp->mx);
4349                 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4350                 lock_ObtainMutex(&fidp->mx);
4351         }
4352
4353         fidp->flags |= SMB_FID_DELETE;
4354         
4355         /* watch for ioctl closes, and read-only opens */
4356     if (fidp->scp != NULL
4357         && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4358          == SMB_FID_OPENWRITE) {
4359                 if (dosTime != 0 && dosTime != -1) {
4360                         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4361             /* This fixes defect 10958 */
4362             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4363                         smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4364                 }
4365         code = cm_FSync(fidp->scp, userp, &req);
4366         }
4367         else 
4368         code = 0;
4369
4370         if (fidp->flags & SMB_FID_DELONCLOSE) {
4371                 cm_scache_t *dscp = fidp->NTopen_dscp;
4372                 char *pathp = fidp->NTopen_pathp;
4373                 char *fullPathp;
4374
4375                 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4376                 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4377                         code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4378                         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4379                                 smb_NotifyChange(FILE_ACTION_REMOVED,
4380                                  FILE_NOTIFY_CHANGE_DIR_NAME,
4381                                  dscp, fullPathp, NULL, TRUE);
4382                 }
4383                 else 
4384         {
4385                         code = cm_Unlink(dscp, fullPathp, userp, &req);
4386                         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4387                                 smb_NotifyChange(FILE_ACTION_REMOVED,
4388                                  FILE_NOTIFY_CHANGE_FILE_NAME,
4389                                  dscp, fullPathp, NULL, TRUE);
4390                 }
4391                 free(fullPathp);
4392         }
4393     lock_ReleaseMutex(&fidp->mx);
4394
4395     if (fidp->flags & SMB_FID_NTOPEN) {
4396                 cm_ReleaseSCache(fidp->NTopen_dscp);
4397                 free(fidp->NTopen_pathp);
4398         }
4399         if (fidp->NTopen_wholepathp)
4400                 free(fidp->NTopen_wholepathp);
4401     
4402     smb_ReleaseFID(fidp);
4403         cm_ReleaseUser(userp);
4404     return code;
4405 }
4406
4407 /*
4408  * smb_ReadData -- common code for Read, Read And X, and Raw Read
4409  */
4410 #ifndef DJGPP
4411 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4412         cm_user_t *userp, long *readp)
4413 #else /* DJGPP */
4414 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4415         cm_user_t *userp, long *readp, int dosflag)
4416 #endif /* !DJGPP */
4417 {
4418         osi_hyper_t offset;
4419         long code;
4420         cm_scache_t *scp;
4421         cm_buf_t *bufferp;
4422         osi_hyper_t fileLength;
4423         osi_hyper_t thyper;
4424         osi_hyper_t lastByte;
4425         osi_hyper_t bufferOffset;
4426         long bufIndex, nbytes;
4427         int chunk;
4428         int sequential = 0;
4429         cm_req_t req;
4430
4431         cm_InitReq(&req);
4432
4433         bufferp = NULL;
4434         offset = *offsetp;
4435
4436         lock_ObtainMutex(&fidp->mx);
4437         scp = fidp->scp;
4438         lock_ObtainMutex(&scp->mx);
4439
4440         if (offset.HighPart == 0) {
4441                 chunk = offset.LowPart >> cm_logChunkSize;
4442                 if (chunk != fidp->curr_chunk) {
4443                         fidp->prev_chunk = fidp->curr_chunk;
4444                         fidp->curr_chunk = chunk;
4445                 }
4446                 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4447                         sequential = 1;
4448         }
4449
4450         /* start by looking up the file's end */
4451         code = cm_SyncOp(scp, NULL, userp, &req, 0,
4452                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4453         if (code) goto done;
4454
4455         /* now we have the entry locked, look up the length */
4456         fileLength = scp->length;
4457
4458         /* adjust count down so that it won't go past EOF */
4459         thyper.LowPart = count;
4460         thyper.HighPart = 0;
4461         thyper = LargeIntegerAdd(offset, thyper);       /* where read should end */
4462         lastByte = thyper;
4463         if (LargeIntegerGreaterThan(thyper, fileLength)) {
4464                 /* we'd read past EOF, so just stop at fileLength bytes.
4465                  * Start by computing how many bytes remain in the file.
4466                  */
4467                 thyper = LargeIntegerSubtract(fileLength, offset);
4468
4469                 /* if we are past EOF, read 0 bytes */
4470                 if (LargeIntegerLessThanZero(thyper))
4471                         count = 0;
4472                 else
4473                         count = thyper.LowPart;
4474         }
4475
4476         *readp = count;
4477
4478         /* now, copy the data one buffer at a time,
4479          * until we've filled the request packet
4480          */
4481         while (1) {
4482                 /* if we've copied all the data requested, we're done */
4483                 if (count <= 0) break;
4484                 
4485                 /* otherwise, load up a buffer of data */
4486                 thyper.HighPart = offset.HighPart;
4487                 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4488                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4489                         /* wrong buffer */
4490                         if (bufferp) {
4491                                 buf_Release(bufferp);
4492                                 bufferp = NULL;
4493                         }
4494                         lock_ReleaseMutex(&scp->mx);
4495
4496                         lock_ObtainRead(&scp->bufCreateLock);
4497                         code = buf_Get(scp, &thyper, &bufferp);
4498                         lock_ReleaseRead(&scp->bufCreateLock);
4499
4500                         lock_ObtainMutex(&scp->mx);
4501                         if (code) goto done;
4502                         bufferOffset = thyper;
4503
4504                         /* now get the data in the cache */
4505                         while (1) {
4506                                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4507                                                                   CM_SCACHESYNC_NEEDCALLBACK
4508                                                                   | CM_SCACHESYNC_READ);
4509                                 if (code) goto done;
4510                                 
4511                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4512
4513                                 /* otherwise, load the buffer and try again */
4514                                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4515                                 if (code) break;
4516                         }
4517                         if (code) {
4518                                 buf_Release(bufferp);
4519                                 bufferp = NULL;
4520                                 goto done;
4521                         }
4522                 }       /* if (wrong buffer) ... */
4523                 
4524                 /* now we have the right buffer loaded.  Copy out the
4525                  * data from here to the user's buffer.
4526                  */
4527                 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4528
4529                 /* and figure out how many bytes we want from this buffer */
4530                 nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
4531                 if (nbytes > count) nbytes = count;     /* don't go past EOF */
4532                 
4533                 /* now copy the data */
4534 #ifdef DJGPP
4535                 if (dosflag)
4536                         dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4537                 else
4538 #endif /* DJGPP */
4539                         memcpy(op, bufferp->datap + bufIndex, nbytes);
4540                 
4541                 /* adjust counters, pointers, etc. */
4542                 op += nbytes;
4543                 count -= nbytes;
4544                 thyper.LowPart = nbytes;
4545                 thyper.HighPart = 0;
4546                 offset = LargeIntegerAdd(thyper, offset);
4547         } /* while 1 */
4548
4549   done:
4550         lock_ReleaseMutex(&scp->mx);
4551         lock_ReleaseMutex(&fidp->mx);
4552         if (bufferp) 
4553                 buf_Release(bufferp);
4554
4555         if (code == 0 && sequential)
4556                 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
4557
4558         return code;
4559 }
4560
4561 /*
4562  * smb_WriteData -- common code for Write and Raw Write
4563  */
4564 #ifndef DJGPP
4565 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4566         cm_user_t *userp, long *writtenp)
4567 #else /* DJGPP */
4568 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4569         cm_user_t *userp, long *writtenp, int dosflag)
4570 #endif /* !DJGPP */
4571 {
4572         osi_hyper_t offset;
4573         long code;
4574         long written = 0;
4575         cm_scache_t *scp;
4576         osi_hyper_t fileLength; /* file's length at start of write */
4577         osi_hyper_t minLength;  /* don't read past this */
4578         long nbytes;            /* # of bytes to transfer this iteration */
4579         cm_buf_t *bufferp;
4580         osi_hyper_t thyper;             /* hyper tmp variable */
4581         osi_hyper_t bufferOffset;
4582         long bufIndex;                  /* index in buffer where our data is */
4583         int doWriteBack;
4584         osi_hyper_t writeBackOffset;    /* offset of region to write back when
4585         * I/O is done */
4586         DWORD filter = 0;
4587         cm_req_t req;
4588
4589         cm_InitReq(&req);
4590
4591         bufferp = NULL;
4592         doWriteBack = 0;
4593         offset = *offsetp;
4594
4595         lock_ObtainMutex(&fidp->mx);
4596         scp = fidp->scp;
4597         lock_ObtainMutex(&scp->mx);
4598
4599         /* start by looking up the file's end */
4600         code = cm_SyncOp(scp, NULL, userp, &req, 0,
4601                                          CM_SCACHESYNC_NEEDCALLBACK
4602                                          | CM_SCACHESYNC_SETSTATUS
4603                                          | CM_SCACHESYNC_GETSTATUS);
4604         if (code) 
4605                 goto done;
4606         
4607         /* make sure we have a writable FD */
4608         if (!(fidp->flags & SMB_FID_OPENWRITE)) {
4609                 code = CM_ERROR_BADFDOP;
4610                 goto done;
4611         }
4612         
4613         /* now we have the entry locked, look up the length */
4614         fileLength = scp->length;
4615         minLength = fileLength;
4616         if (LargeIntegerGreaterThan(minLength, scp->serverLength))
4617                 minLength = scp->serverLength;
4618
4619         /* adjust file length if we extend past EOF */
4620         thyper.LowPart = count;
4621         thyper.HighPart = 0;
4622         thyper = LargeIntegerAdd(offset, thyper);       /* where write should end */
4623         if (LargeIntegerGreaterThan(thyper, fileLength)) {
4624                 /* we'd write past EOF, so extend the file */
4625                 scp->mask |= CM_SCACHEMASK_LENGTH;
4626                 scp->length = thyper;
4627                 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
4628         } else
4629                 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
4630         
4631         /* now, if the new position (thyper) and the old (offset) are in
4632          * different storeback windows, remember to store back the previous
4633          * storeback window when we're done with the write.
4634          */
4635         if ((thyper.LowPart & (-cm_chunkSize)) !=
4636                  (offset.LowPart & (-cm_chunkSize))) {
4637                 /* they're different */
4638                 doWriteBack = 1;
4639                 writeBackOffset.HighPart = offset.HighPart;
4640                 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
4641         }
4642         
4643         *writtenp = count;
4644
4645         /* now, copy the data one buffer at a time, until we've filled the
4646          * request packet */
4647         while (1) {
4648                 /* if we've copied all the data requested, we're done */
4649                 if (count <= 0) break;
4650
4651                 /* handle over quota or out of space */
4652                 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
4653                         *writtenp = written;
4654                         break;
4655                 }
4656                 
4657                 /* otherwise, load up a buffer of data */
4658                 thyper.HighPart = offset.HighPart;
4659                 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4660                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4661                         /* wrong buffer */
4662                         if (bufferp) {
4663                                 lock_ReleaseMutex(&bufferp->mx);
4664                                 buf_Release(bufferp);
4665                                 bufferp = NULL;
4666                         }       
4667                         lock_ReleaseMutex(&scp->mx);
4668
4669                         lock_ObtainRead(&scp->bufCreateLock);
4670                         code = buf_Get(scp, &thyper, &bufferp);
4671                         lock_ReleaseRead(&scp->bufCreateLock);
4672
4673                         lock_ObtainMutex(&bufferp->mx);
4674                         lock_ObtainMutex(&scp->mx);
4675                         if (code) goto done;
4676
4677                         bufferOffset = thyper;
4678
4679                         /* now get the data in the cache */
4680                         while (1) {
4681                                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4682                                                                  CM_SCACHESYNC_NEEDCALLBACK
4683                                                                  | CM_SCACHESYNC_WRITE
4684                                                                  | CM_SCACHESYNC_BUFLOCKED);
4685                                 if (code) 
4686                                         goto done;
4687                                 
4688                                 /* If we're overwriting the entire buffer, or
4689                                  * if we're writing at or past EOF, mark the
4690                                  * buffer as current so we don't call
4691                                  * cm_GetBuffer.  This skips the fetch from the
4692                                  * server in those cases where we're going to 
4693                                  * obliterate all the data in the buffer anyway,
4694                                  * or in those cases where there is no useful
4695                                  * data at the server to start with.
4696                                  *
4697                                  * Use minLength instead of scp->length, since
4698                                  * the latter has already been updated by this
4699                                  * call.
4700                                  */
4701                                 if (LargeIntegerGreaterThanOrEqualTo(
4702                                         bufferp->offset, minLength)
4703                                     || LargeIntegerEqualTo(offset, bufferp->offset)
4704                                        && (count >= buf_bufferSize
4705                                            || LargeIntegerGreaterThanOrEqualTo(
4706                                                LargeIntegerAdd(offset,
4707                                                    ConvertLongToLargeInteger(count)),
4708                                                minLength))) {
4709                                         if (count < buf_bufferSize
4710                                             && bufferp->dataVersion == -1)
4711                                             memset(bufferp->datap, 0,
4712                                                    buf_bufferSize);
4713                                         bufferp->dataVersion = scp->dataVersion;
4714                                 }
4715
4716                                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
4717
4718                                 /* otherwise, load the buffer and try again */
4719                                 lock_ReleaseMutex(&bufferp->mx);
4720                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4721                                                                         &req);
4722                                 lock_ReleaseMutex(&scp->mx);
4723                                 lock_ObtainMutex(&bufferp->mx);
4724                                 lock_ObtainMutex(&scp->mx);
4725                                 if (code) break;
4726                         }
4727                         if (code) {
4728                                 lock_ReleaseMutex(&bufferp->mx);
4729                                 buf_Release(bufferp);
4730                                 bufferp = NULL;
4731                                 goto done;
4732                         }
4733                 }       /* if (wrong buffer) ... */
4734                 
4735                 /* now we have the right buffer loaded.  Copy out the
4736                  * data from here to the user's buffer.
4737                  */
4738                 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4739
4740                 /* and figure out how many bytes we want from this buffer */
4741                 nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
4742                 if (nbytes > count) 
4743                         nbytes = count; /* don't go past end of request */
4744                 
4745                 /* now copy the data */
4746 #ifdef DJGPP
4747                 if (dosflag)
4748                         dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
4749                 else
4750 #endif /* DJGPP */
4751                         memcpy(bufferp->datap + bufIndex, op, nbytes);
4752                 buf_SetDirty(bufferp);
4753
4754                 /* and record the last writer */
4755                 if (bufferp->userp != userp) {
4756                         if (bufferp->userp) cm_ReleaseUser(bufferp->userp);
4757                         bufferp->userp = userp;
4758                         cm_HoldUser(userp);
4759                 }
4760                 
4761                 /* adjust counters, pointers, etc. */
4762                 op += nbytes;
4763                 count -= nbytes;
4764                 written += nbytes;
4765                 thyper.LowPart = nbytes;
4766                 thyper.HighPart = 0;
4767                 offset = LargeIntegerAdd(thyper, offset);
4768         } /* while 1 */
4769
4770   done:
4771         lock_ReleaseMutex(&scp->mx);
4772         lock_ReleaseMutex(&fidp->mx);
4773         if (bufferp) {
4774                 lock_ReleaseMutex(&bufferp->mx);
4775                 buf_Release(bufferp);
4776         }
4777
4778         if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
4779             && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
4780                 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
4781                                                  fidp->NTopen_dscp, fidp->NTopen_pathp,
4782                                                  NULL, TRUE);
4783         }
4784
4785         if (code == 0 && doWriteBack) {
4786                 lock_ObtainMutex(&scp->mx);
4787                 cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
4788                 lock_ReleaseMutex(&scp->mx);
4789                 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
4790                                                    writeBackOffset.HighPart, cm_chunkSize, 0, userp);
4791         }
4792
4793         return code;
4794 }
4795
4796 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4797 {
4798         osi_hyper_t offset;
4799     long count, written = 0;
4800     unsigned short fd;
4801     smb_fid_t *fidp;
4802     long code;
4803     cm_user_t *userp;
4804     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
4805     char *op;
4806     int inDataBlockCount;
4807
4808     fd = smb_GetSMBParm(inp, 0);
4809     count = smb_GetSMBParm(inp, 1);
4810     offset.HighPart = 0;        /* too bad */
4811     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
4812
4813     op = smb_GetSMBData(inp, NULL);
4814         op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
4815
4816     osi_Log3(afsd_logp, "smb_ReceiveCoreWrite fd %d, off 0x%x, size 0x%x",
4817              fd, offset.LowPart, count);
4818         
4819         fd = smb_ChainFID(fd, inp);
4820     fidp = smb_FindFID(vcp, fd, 0);
4821     if (!fidp) {
4822                 return CM_ERROR_BADFD;
4823     }
4824         
4825     if (fidp->flags & SMB_FID_IOCTL)
4826         return smb_IoctlWrite(fidp, vcp, inp, outp);
4827         
4828         userp = smb_GetUser(vcp, inp);
4829
4830         /* special case: 0 bytes transferred means truncate to this position */
4831     if (count == 0) {
4832                 cm_req_t req;
4833
4834                 cm_InitReq(&req);
4835
4836                 truncAttr.mask = CM_ATTRMASK_LENGTH;
4837         truncAttr.length.LowPart = offset.LowPart;
4838         truncAttr.length.HighPart = 0;
4839                 lock_ObtainMutex(&fidp->mx);
4840         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
4841                 lock_ReleaseMutex(&fidp->mx);
4842                 smb_SetSMBParm(outp, 0, /* count */ 0);
4843         smb_SetSMBDataLength(outp, 0);
4844                 fidp->flags |= SMB_FID_LENGTHSETDONE;
4845         goto done;
4846     }
4847
4848         /*
4849          * Work around bug in NT client
4850          *
4851          * When copying a file, the NT client should first copy the data,
4852          * then copy the last write time.  But sometimes the NT client does
4853          * these in the wrong order, so the data copies would inadvertently
4854          * cause the last write time to be overwritten.  We try to detect this,
4855          * and don't set client mod time if we think that would go against the
4856          * intention.
4857          */
4858         if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
4859                 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4860                 fidp->scp->clientModTime = time(NULL);
4861         }
4862
4863 #ifndef DJGPP
4864         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
4865 #else /* DJGPP */
4866         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
4867 #endif /* !DJGPP */
4868         if (code == 0 && written < count)
4869                 code = CM_ERROR_PARTIALWRITE;
4870
4871         /* set the packet data length to 3 bytes for the data block header,
4872      * plus the size of the data.
4873      */
4874         smb_SetSMBParm(outp, 0, written);
4875     smb_SetSMBDataLength(outp, 0);
4876
4877   done:
4878     smb_ReleaseFID(fidp);
4879     cm_ReleaseUser(userp);
4880
4881         return code;
4882 }
4883
4884 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
4885         NCB *ncbp, raw_write_cont_t *rwcp)
4886 {
4887         unsigned short fd;
4888         smb_fid_t *fidp;
4889         cm_user_t *userp;
4890 #ifndef DJGPP
4891         char *rawBuf;
4892 #else /* DJGPP */
4893         dos_ptr rawBuf;
4894 #endif /* !DJGPP */
4895         long written = 0;
4896         long code;
4897
4898         fd = smb_GetSMBParm(inp, 0);
4899         fidp = smb_FindFID(vcp, fd, 0);
4900
4901         osi_Log2(afsd_logp, "Completing Raw Write offset %x count %x",
4902                  rwcp->offset.LowPart, rwcp->count);
4903
4904         userp = smb_GetUser(vcp, inp);
4905
4906 #ifndef DJGPP
4907         rawBuf = rwcp->buf;
4908         code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
4909                                                  &written);
4910 #else /* DJGPP */
4911         rawBuf = (dos_ptr) rwcp->buf;
4912         code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
4913                          (unsigned char *) rawBuf, userp,
4914                          &written, TRUE);
4915 #endif /* !DJGPP */
4916
4917         if (rwcp->writeMode & 0x1) {    /* synchronous */
4918                 smb_t *op;
4919
4920                 smb_FormatResponsePacket(vcp, inp, outp);
4921                 op = (smb_t *) outp;
4922                 op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
4923                 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
4924                 smb_SetSMBDataLength(outp,  0);
4925                 smb_SendPacket(vcp, outp);
4926                 smb_FreePacket(outp);
4927         }
4928         else {                          /* asynchronous */
4929                 lock_ObtainMutex(&fidp->mx);
4930                 fidp->raw_writers--;
4931                 if (fidp->raw_writers == 0)
4932                         thrd_SetEvent(fidp->raw_write_event);
4933                 lock_ReleaseMutex(&fidp->mx);
4934         }
4935
4936         /* Give back raw buffer */
4937         lock_ObtainMutex(&smb_RawBufLock);
4938 #ifndef DJGPP
4939         *((char **)rawBuf) = smb_RawBufs;
4940 #else /* DJGPP */
4941     _farpokel(_dos_ds, rawBuf, smb_RawBufs);
4942 #endif /* !DJGPP */
4943         smb_RawBufs = rawBuf;
4944         lock_ReleaseMutex(&smb_RawBufLock);
4945
4946         smb_ReleaseFID(fidp);
4947         cm_ReleaseUser(userp);
4948 }
4949
4950 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4951 {
4952         return 0;
4953 }
4954
4955 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
4956 {
4957         osi_hyper_t offset;
4958     long count, written = 0;
4959         long totalCount;
4960     unsigned short fd;
4961     smb_fid_t *fidp;
4962     long code;
4963     cm_user_t *userp;
4964     char *op;
4965         unsigned short writeMode;
4966 #ifndef DJGPP
4967         char *rawBuf;
4968 #else /* DJGPP */
4969     dos_ptr rawBuf;
4970 #endif /* !DJGPP */
4971
4972     fd = smb_GetSMBParm(inp, 0);
4973         totalCount = smb_GetSMBParm(inp, 1);
4974     count = smb_GetSMBParm(inp, 10);
4975     offset.HighPart = 0;        /* too bad */
4976     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4977         writeMode = smb_GetSMBParm(inp, 7);
4978
4979         op = (char *) inp->data;
4980         op += smb_GetSMBParm(inp, 11);
4981
4982     osi_Log4(afsd_logp,
4983              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
4984              fd, offset.LowPart, count, writeMode);
4985         
4986         fd = smb_ChainFID(fd, inp);
4987     fidp = smb_FindFID(vcp, fd, 0);
4988     if (!fidp) {
4989                 return CM_ERROR_BADFD;
4990     }
4991         
4992         userp = smb_GetUser(vcp, inp);
4993
4994         /*
4995          * Work around bug in NT client
4996          *
4997          * When copying a file, the NT client should first copy the data,
4998          * then copy the last write time.  But sometimes the NT client does
4999          * these in the wrong order, so the data copies would inadvertently
5000          * cause the last write time to be overwritten.  We try to detect this,
5001          * and don't set client mod time if we think that would go against the
5002          * intention.
5003          */
5004         if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5005                 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5006                 fidp->scp->clientModTime = time(NULL);
5007         }
5008
5009 #ifndef DJGPP
5010         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5011 #else /* DJGPP */
5012         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5013 #endif /* !DJGPP */
5014         if (code == 0 && written < count)
5015                 code = CM_ERROR_PARTIALWRITE;
5016
5017         /* Get a raw buffer */
5018         if (code == 0) {
5019                 rawBuf = NULL;
5020                 lock_ObtainMutex(&smb_RawBufLock);
5021                 if (smb_RawBufs) {
5022                         /* Get a raw buf, from head of list */
5023                         rawBuf = smb_RawBufs;
5024 #ifndef DJGPP
5025                         smb_RawBufs = *(char **)smb_RawBufs;
5026 #else /* DJGPP */
5027             smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5028 #endif /* !DJGPP */
5029                 }
5030                 else
5031                         code = CM_ERROR_USESTD;
5032                 
5033         lock_ReleaseMutex(&smb_RawBufLock);
5034         }
5035
5036         /* Don't allow a premature Close */
5037         if (code == 0 && (writeMode & 1) == 0) {
5038                 lock_ObtainMutex(&fidp->mx);
5039                 fidp->raw_writers++;
5040                 thrd_ResetEvent(fidp->raw_write_event);
5041                 lock_ReleaseMutex(&fidp->mx);
5042         }
5043
5044         smb_ReleaseFID(fidp);
5045         cm_ReleaseUser(userp);
5046
5047         if (code) {
5048                 smb_SetSMBParm(outp, 0, written);
5049                 smb_SetSMBDataLength(outp, 0);
5050                 ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
5051                 rwcp->code = code;
5052                 return code;
5053         }
5054
5055         rwcp->code = 0;
5056         rwcp->buf = rawBuf;
5057         rwcp->offset.HighPart = 0;
5058         rwcp->offset.LowPart = offset.LowPart + count;
5059         rwcp->count = totalCount - count;
5060         rwcp->writeMode = writeMode;
5061         rwcp->alreadyWritten = written;
5062
5063         /* set the packet data length to 3 bytes for the data block header,
5064      * plus the size of the data.
5065      */
5066         smb_SetSMBParm(outp, 0, 0xffff);
5067     smb_SetSMBDataLength(outp, 0);
5068
5069         return 0;
5070 }
5071
5072 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5073 {
5074         osi_hyper_t offset;
5075     long count, finalCount;
5076     unsigned short fd;
5077     smb_fid_t *fidp;
5078     long code;
5079     cm_user_t *userp;
5080     char *op;
5081         
5082     fd = smb_GetSMBParm(inp, 0);
5083     count = smb_GetSMBParm(inp, 1);
5084     offset.HighPart = 0;        /* too bad */
5085     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5086         
5087     osi_Log3(afsd_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5088              fd, offset.LowPart, count);
5089         
5090         fd = smb_ChainFID(fd, inp);
5091     fidp = smb_FindFID(vcp, fd, 0);
5092     if (!fidp) {
5093                 return CM_ERROR_BADFD;
5094     }
5095         
5096     if (fidp->flags & SMB_FID_IOCTL) {
5097                 return smb_IoctlRead(fidp, vcp, inp, outp);
5098     }
5099         
5100         userp = smb_GetUser(vcp, inp);
5101
5102         /* remember this for final results */
5103     smb_SetSMBParm(outp, 0, count);
5104     smb_SetSMBParm(outp, 1, 0);
5105     smb_SetSMBParm(outp, 2, 0);
5106     smb_SetSMBParm(outp, 3, 0);
5107     smb_SetSMBParm(outp, 4, 0);
5108
5109         /* set the packet data length to 3 bytes for the data block header,
5110      * plus the size of the data.
5111      */
5112     smb_SetSMBDataLength(outp, count+3);
5113         
5114         /* get op ptr after putting in the parms, since otherwise we don't
5115      * know where the data really is.
5116      */
5117     op = smb_GetSMBData(outp, NULL);
5118
5119         /* now emit the data block header: 1 byte of type and 2 bytes of length */
5120     *op++ = 1;  /* data block marker */
5121     *op++ = (unsigned char) (count & 0xff);
5122     *op++ = (unsigned char) ((count >> 8) & 0xff);
5123                 
5124 #ifndef DJGPP
5125         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5126 #else /* DJGPP */
5127     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5128 #endif /* !DJGPP */
5129
5130         /* fix some things up */
5131         smb_SetSMBParm(outp, 0, finalCount);
5132         smb_SetSMBDataLength(outp, finalCount+3);
5133
5134     smb_ReleaseFID(fidp);
5135         
5136     cm_ReleaseUser(userp);
5137     return code;
5138 }
5139
5140 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5141 {
5142         char *pathp;
5143     long code;
5144         cm_space_t *spacep;
5145     char *tp;
5146     cm_user_t *userp;
5147     cm_scache_t *dscp;                  /* dir we're dealing with */
5148     cm_scache_t *scp;                   /* file we're creating */
5149     cm_attr_t setAttr;
5150     int initialModeBits;
5151     char *lastNamep;
5152     int caseFold;
5153         char *tidPathp;
5154         cm_req_t req;
5155
5156         cm_InitReq(&req);
5157
5158     scp = NULL;
5159         
5160         /* compute initial mode bits based on read-only flag in attributes */
5161     initialModeBits = 0777;
5162         
5163         tp = smb_GetSMBData(inp, NULL);
5164     pathp = smb_ParseASCIIBlock(tp, &tp);
5165
5166         if (strcmp(pathp, "\\") == 0)
5167                 return CM_ERROR_EXISTS;
5168
5169         spacep = inp->spacep;
5170     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5171
5172         userp = smb_GetUser(vcp, inp);
5173
5174     caseFold = CM_FLAG_CASEFOLD;
5175
5176         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5177
5178         code = cm_NameI(cm_rootSCachep, spacep->data,
5179                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5180                     userp, tidPathp, &req, &dscp);
5181
5182     if (code) {
5183         cm_ReleaseUser(userp);
5184         return code;
5185     }
5186         
5187     /* otherwise, scp points to the parent directory.  Do a lookup, and
5188          * fail if we find it.  Otherwise, we do the create.
5189      */
5190     if (!lastNamep) 
5191         lastNamep = pathp;
5192     else 
5193         lastNamep++;
5194     code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
5195     if (scp) cm_ReleaseSCache(scp);
5196     if (code != CM_ERROR_NOSUCHFILE) {
5197         if (code == 0) code = CM_ERROR_EXISTS;
5198                 cm_ReleaseSCache(dscp);
5199         cm_ReleaseUser(userp);
5200         return code;
5201     }
5202         
5203         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5204         setAttr.clientModTime = time(NULL);
5205         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5206         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5207                 smb_NotifyChange(FILE_ACTION_ADDED,
5208                          FILE_NOTIFY_CHANGE_DIR_NAME,
5209                          dscp, lastNamep, NULL, TRUE);
5210         
5211         /* we don't need this any longer */
5212         cm_ReleaseSCache(dscp);
5213
5214     if (code) {
5215                 /* something went wrong creating or truncating the file */
5216         cm_ReleaseUser(userp);
5217         return code;
5218     }
5219         
5220         /* otherwise we succeeded */
5221     smb_SetSMBDataLength(outp, 0);
5222     cm_ReleaseUser(userp);
5223
5224     return 0;
5225 }
5226
5227 BOOL smb_IsLegalFilename(char *filename)
5228 {
5229     /* 
5230      *  Find the longest substring of filename that does not contain
5231      *  any of the chars in illegalChars.  If that substring is less
5232      *  than the length of the whole string, then one or more of the
5233      *  illegal chars is in filename. 
5234      */
5235     if (strcspn(filename, illegalChars) < strlen(filename))
5236         return FALSE;
5237
5238     return TRUE;
5239 }        
5240
5241 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5242 {
5243         char *pathp;
5244     long code;
5245         cm_space_t *spacep;
5246     char *tp;
5247     int excl;
5248     cm_user_t *userp;
5249     cm_scache_t *dscp;                  /* dir we're dealing with */
5250     cm_scache_t *scp;                   /* file we're creating */
5251     cm_attr_t setAttr;
5252     int initialModeBits;
5253     smb_fid_t *fidp;
5254     int attributes;
5255     char *lastNamep;
5256     int caseFold;
5257     long dosTime;
5258         char *tidPathp;
5259         cm_req_t req;
5260
5261         cm_InitReq(&req);
5262
5263     scp = NULL;
5264     excl = (inp->inCom == 0x03)? 0 : 1;
5265         
5266     attributes = smb_GetSMBParm(inp, 0);
5267     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5268         
5269         /* compute initial mode bits based on read-only flag in attributes */
5270     initialModeBits = 0666;
5271     if (attributes & 1) initialModeBits &= ~0222;
5272         
5273         tp = smb_GetSMBData(inp, NULL);
5274     pathp = smb_ParseASCIIBlock(tp, &tp);
5275
5276         spacep = inp->spacep;
5277     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5278
5279         userp = smb_GetUser(vcp, inp);
5280
5281     caseFold = CM_FLAG_CASEFOLD;
5282
5283         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5284         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5285                     userp, tidPathp, &req, &dscp);
5286
5287     if (code) {
5288         cm_ReleaseUser(userp);
5289         return code;
5290     }
5291         
5292     /* otherwise, scp points to the parent directory.  Do a lookup, and
5293          * truncate the file if we find it, otherwise we create the file.
5294      */
5295     if (!lastNamep) lastNamep = pathp;
5296     else lastNamep++;
5297
5298     if (!smb_IsLegalFilename(lastNamep))
5299         return CM_ERROR_BADNTFILENAME;
5300
5301     osi_Log1(afsd_logp, "SMB receive create [%s]", osi_LogSaveString( afsd_logp, pathp ));
5302 #ifdef DEBUG_VERBOSE
5303     {
5304         char *hexp;
5305         hexp = osi_HexifyString( lastNamep );
5306         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5307         free(hexp);
5308     }
5309 #endif    
5310
5311     code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
5312     if (code && code != CM_ERROR_NOSUCHFILE) {
5313                 cm_ReleaseSCache(dscp);
5314         cm_ReleaseUser(userp);
5315         return code;
5316     }
5317         
5318     /* if we get here, if code is 0, the file exists and is represented by
5319      * scp.  Otherwise, we have to create it.
5320      */
5321         if (code == 0) {
5322                 if (excl) {
5323                         /* oops, file shouldn't be there */
5324             cm_ReleaseSCache(dscp);
5325             cm_ReleaseSCache(scp);
5326             cm_ReleaseUser(userp);
5327             return CM_ERROR_EXISTS;
5328         }
5329
5330                 setAttr.mask = CM_ATTRMASK_LENGTH;
5331         setAttr.length.LowPart = 0;
5332         setAttr.length.HighPart = 0;
5333                 code = cm_SetAttr(scp, &setAttr, userp, &req);
5334     }
5335     else {
5336                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5337                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5338         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5339                          &req);
5340                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5341                         smb_NotifyChange(FILE_ACTION_ADDED,
5342                              FILE_NOTIFY_CHANGE_FILE_NAME,
5343                              dscp, lastNamep, NULL, TRUE);
5344         if (!excl && code == CM_ERROR_EXISTS) {
5345                         /* not an exclusive create, and someone else tried
5346                          * creating it already, then we open it anyway.  We
5347                          * don't bother retrying after this, since if this next
5348                          * fails, that means that the file was deleted after
5349                          * we started this call.
5350              */
5351             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5352                              &req, &scp);
5353             if (code == 0) {
5354                                 setAttr.mask = CM_ATTRMASK_LENGTH;
5355                 setAttr.length.LowPart = 0;
5356                 setAttr.length.HighPart = 0;
5357                 code = cm_SetAttr(scp, &setAttr, userp, &req);
5358             }
5359         }
5360     }
5361         
5362         /* we don't need this any longer */
5363         cm_ReleaseSCache(dscp);
5364
5365     if (code) {
5366                 /* something went wrong creating or truncating the file */
5367         if (scp) cm_ReleaseSCache(scp);
5368         cm_ReleaseUser(userp);
5369         return code;
5370     }
5371
5372         /* make sure we only open files */
5373         if (scp->fileType != CM_SCACHETYPE_FILE) {
5374                 cm_ReleaseSCache(scp);
5375         cm_ReleaseUser(userp);
5376         return CM_ERROR_ISDIR;
5377         }
5378
5379     /* now all we have to do is open the file itself */
5380     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5381     osi_assert(fidp);
5382         
5383         /* save a pointer to the vnode */
5384     fidp->scp = scp;
5385         
5386         /* always create it open for read/write */
5387         fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5388
5389         smb_ReleaseFID(fidp);
5390         
5391         smb_SetSMBParm(outp, 0, fidp->fid);
5392     smb_SetSMBDataLength(outp, 0);
5393
5394         cm_Open(scp, 0, userp);
5395
5396     cm_ReleaseUser(userp);
5397     /* leave scp held since we put it in fidp->scp */
5398     return 0;
5399 }
5400
5401 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5402 {
5403     long code;
5404     long offset;
5405     int whence;
5406     unsigned short fd;
5407     smb_fid_t *fidp;
5408     cm_scache_t *scp;
5409     cm_user_t *userp;
5410         cm_req_t req;
5411
5412         cm_InitReq(&req);
5413         
5414     fd = smb_GetSMBParm(inp, 0);
5415         whence = smb_GetSMBParm(inp, 1);
5416     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5417         
5418         /* try to find the file descriptor */
5419         fd = smb_ChainFID(fd, inp);
5420     fidp = smb_FindFID(vcp, fd, 0);
5421     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5422                 return CM_ERROR_BADFD;
5423     }
5424         
5425         userp = smb_GetUser(vcp, inp);
5426
5427     lock_ObtainMutex(&fidp->mx);
5428     scp = fidp->scp;
5429         lock_ObtainMutex(&scp->mx);
5430         code = cm_SyncOp(scp, NULL, userp, &req, 0,
5431                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5432         if (code == 0) {
5433                 if (whence == 1) {
5434             /* offset from current offset */
5435             offset += fidp->offset;
5436                 }
5437                 else if (whence == 2) {
5438             /* offset from current EOF */
5439             offset += scp->length.LowPart;
5440                 }
5441         fidp->offset = offset;
5442         smb_SetSMBParm(outp, 0, offset & 0xffff);
5443         smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5444         smb_SetSMBDataLength(outp, 0);
5445     }
5446         lock_ReleaseMutex(&scp->mx);
5447     lock_ReleaseMutex(&fidp->mx);
5448     smb_ReleaseFID(fidp);
5449     cm_ReleaseUser(userp);
5450     return code;
5451 }
5452
5453 /* dispatch all of the requests received in a packet.  Due to chaining, this may
5454  * be more than one request.
5455  */
5456 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5457         NCB *ncbp, raw_write_cont_t *rwcp)
5458 {
5459     static showErrors = 0;
5460     smb_dispatch_t *dp;
5461     smb_t *smbp;
5462     unsigned long code;
5463     unsigned char *outWctp;
5464     int nparms;                 /* # of bytes of parameters */
5465     char tbuffer[200];
5466     int nbytes;                 /* bytes of data, excluding count */
5467     int temp;
5468     unsigned char *tp;
5469     unsigned short errCode;
5470         unsigned long NTStatus;
5471     int noSend;
5472     unsigned char errClass;
5473         unsigned int oldGen;
5474         DWORD oldTime, newTime;
5475
5476         /* get easy pointer to the data */
5477         smbp = (smb_t *) inp->data;
5478
5479         if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5480         /* setup the basic parms for the initial request in the packet */
5481                 inp->inCom = smbp->com;
5482         inp->wctp = &smbp->wct;
5483         inp->inCount = 0;
5484                 inp->ncb_length = ncbp->ncb_length;
5485         }
5486     noSend = 0;
5487
5488         /* Sanity check */
5489         if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5490                 /* log it and discard it */
5491 #ifndef DJGPP
5492                 HANDLE h;
5493                 char *ptbuf[1];
5494                 char s[100];
5495                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5496                 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5497                 ptbuf[0] = s;
5498                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5499                         1, ncbp->ncb_length, ptbuf, inp);
5500                 DeregisterEventSource(h);
5501 #else /* DJGPP */
5502         osi_Log1(smb_logp, "SMB message too short, len %d",
5503                  ncbp->ncb_length);
5504 #endif /* !DJGPP */
5505
5506                 return;
5507         }
5508
5509         /* We are an ongoing op */
5510         thrd_Increment(&ongoingOps);
5511
5512     /* set up response packet for receiving output */
5513         if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5514         smb_FormatResponsePacket(vcp, inp, outp);
5515     outWctp = outp->wctp;
5516
5517         /* Remember session generation number and time */
5518         oldGen = sessionGen;
5519         oldTime = GetCurrentTime();
5520
5521         while(inp->inCom != 0xff) {
5522         dp = &smb_dispatchTable[inp->inCom];
5523
5524                 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5525                         outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5526                         code = outp->resumeCode;
5527                         goto resume;
5528                 }
5529
5530         /* process each request in the packet; inCom, wctp and inCount
5531          * are already set up.
5532          */
5533                 osi_Log2(afsd_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5534                  ncbp->ncb_lsn);
5535
5536                 /* now do the dispatch */
5537                 /* start by formatting the response record a little, as a default */
5538         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
5539                         outWctp[0] = 2;
5540             outWctp[1] = 0xff;  /* no operation */
5541             outWctp[2] = 0;             /* padding */
5542             outWctp[3] = 0;
5543             outWctp[4] = 0;
5544         }
5545                 else {
5546                         /* not a chained request, this is a more reasonable default */
5547             outWctp[0] = 0;     /* wct of zero */
5548             outWctp[1] = 0;     /* and bcc (word) of zero */
5549             outWctp[2] = 0;
5550                 }   
5551
5552                 /* once set, stays set.  Doesn't matter, since we never chain
5553          * "no response" calls.
5554          */
5555                 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
5556             noSend = 1;
5557
5558         if (dp->procp) {
5559                         /* we have a recognized operation */
5560
5561                         if (inp->inCom == 0x1d)
5562                                 /* Raw Write */
5563                                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
5564                                                 rwcp);
5565                         else {
5566                                         osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
5567                                         osi_Log4(afsd_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
5568                                         code = (*(dp->procp)) (vcp, inp, outp);
5569                                         osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5570                                         osi_Log1(afsd_logp,"Dispatch return  code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5571             }
5572
5573                         if (oldGen != sessionGen) {
5574 #ifndef DJGPP
5575                                 HANDLE h;
5576                                 char *ptbuf[1];
5577                                 char s[100];
5578                                 newTime = GetCurrentTime();
5579                                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5580                                 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
5581                         newTime - oldTime, ncbp->ncb_length);
5582                                 ptbuf[0] = s;
5583                                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
5584                             1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
5585                                 DeregisterEventSource(h);
5586 #else /* DJGPP */
5587                                 osi_Log1(afsd_logp, "Pkt straddled session startup, "
5588                          "ncb length %d", ncbp->ncb_length);
5589 #endif /* !DJGPP */
5590                         }
5591         }
5592         else {
5593                         /* bad opcode, fail the request, after displaying it */
5594 #ifdef NOTSERVICE
5595             smb_LogPacket(inp);
5596 #endif  /* NOTSERVICE */
5597
5598 #ifndef DJGPP
5599                         if (showErrors) {
5600                                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
5601                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
5602                                      MB_OKCANCEL);
5603                 if (code == IDCANCEL) showErrors = 0;
5604                         }
5605 #endif /* DJGPP */
5606             code = CM_ERROR_BADOP;
5607         }
5608
5609                 /* catastrophic failure:  log as much as possible */
5610                 if (code == CM_ERROR_BADSMB) {
5611 #ifndef DJGPP
5612                         HANDLE h;
5613                         char *ptbuf[1];
5614                         char s[100];
5615
5616                         osi_Log1(smb_logp,
5617                       "Invalid SMB, ncb_length %d",
5618                       ncbp->ncb_length);
5619
5620                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5621                         sprintf(s, "Invalid SMB message, length %d",
5622                      ncbp->ncb_length);
5623                         ptbuf[0] = s;
5624                         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
5625                          1, ncbp->ncb_length, ptbuf, smbp);
5626                         DeregisterEventSource(h);
5627 #ifdef NOTSERVICE
5628             smb_LogPacket(inp);
5629 #endif /* NOTSERVICE */
5630 #else /* DJGPP */
5631             osi_Log1(afsd_logp, "Invalid SMB message, length %d",
5632                      ncbp->ncb_length);
5633 #endif /* !DJGPP */
5634
5635                         code = CM_ERROR_INVAL;
5636                 }
5637
5638                 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
5639                         thrd_Decrement(&ongoingOps);
5640                         return;
5641                 }
5642
5643       resume:
5644                 /* now, if we failed, turn the current response into an empty
5645          * one, and fill in the response packet's error code.
5646          */
5647                 if (code) {
5648                         if (vcp->flags & SMB_VCFLAG_STATUS32) {
5649                                 smb_MapNTError(code, &NTStatus);
5650                                 outWctp = outp->wctp;
5651                                 smbp = (smb_t *) &outp->data;
5652                                 if (code != CM_ERROR_PARTIALWRITE
5653                                     && code != CM_ERROR_BUFFERTOOSMALL) {
5654                                         /* nuke wct and bcc.  For a partial
5655                                          * write, assume they're OK.
5656                                          */
5657                                         *outWctp++ = 0;
5658                                         *outWctp++ = 0;
5659                                         *outWctp++ = 0;
5660                                 }
5661                                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
5662                                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
5663                                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
5664                                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
5665                                 smbp->flg2 |= 0x4000;
5666                                 break;
5667                         }
5668                         else {
5669                 smb_MapCoreError(code, vcp, &errCode, &errClass);
5670                                 outWctp = outp->wctp;
5671                                 smbp = (smb_t *) &outp->data;
5672                                 if (code != CM_ERROR_PARTIALWRITE) {
5673                                         /* nuke wct and bcc.  For a partial
5674                                          * write, assume they're OK.
5675                                          */
5676                                         *outWctp++ = 0;
5677                                         *outWctp++ = 0;
5678                                         *outWctp++ = 0;
5679                                 }
5680                                 smbp->errLow = (unsigned char) (errCode & 0xff);
5681                                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
5682                 smbp->rcls = errClass;
5683                                 break;
5684                         }
5685                 }       /* error occurred */
5686                 
5687         /* if we're here, we've finished one request.  Look to see if
5688                  * this is a chained opcode.  If it is, setup things to process
5689                  * the chained request, and setup the output buffer to hold the
5690                  * chained response.  Start by finding the next input record.
5691          */
5692         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
5693             break;              /* not a chained req */
5694         tp = inp->wctp;         /* points to start of last request */
5695         /* in a chained request, the first two
5696          * parm fields are required, and are
5697          * AndXCommand/AndXReserved and
5698          * AndXOffset. */
5699         if (tp[0] < 2) break;   
5700         if (tp[1] == 0xff) break;       /* no more chained opcodes */
5701         inp->inCom = tp[1];
5702         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
5703         inp->inCount++;
5704
5705         /* and now append the next output request to the end of this
5706          * last request.  Begin by finding out where the last response
5707                  * ends, since that's where we'll put our new response.
5708          */
5709         outWctp = outp->wctp;           /* ptr to out parameters */
5710         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
5711         nparms = outWctp[0] << 1;
5712         tp = outWctp + nparms + 1;      /* now points to bcc field */
5713         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
5714         tp += 2 /* for the count itself */ + nbytes;
5715                 /* tp now points to the new output record; go back and patch the
5716          * second parameter (off2) to point to the new record.
5717          */
5718                 temp = (unsigned int)tp - ((unsigned int) outp->data);
5719         outWctp[3] = (unsigned char) (temp & 0xff);
5720         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
5721         outWctp[2] = 0; /* padding */
5722         outWctp[1] = inp->inCom;        /* next opcode */
5723
5724                 /* finally, setup for the next iteration */
5725         outp->wctp = tp;
5726                 outWctp = tp;
5727         }       /* while loop over all requests in the packet */
5728
5729         /* done logging out, turn off logging-out flag */
5730         if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
5731                 vcp->justLoggedOut = NULL;
5732                 if (loggedOut) {
5733                         loggedOut = 0;
5734                         free(loggedOutName);
5735                         loggedOutName = NULL;
5736                         smb_ReleaseUID(loggedOutUserp);
5737                         loggedOutUserp = NULL;
5738                 }
5739         }
5740  
5741     /* now send the output packet, and return */
5742     if (!noSend)
5743                 smb_SendPacket(vcp, outp);
5744         thrd_Decrement(&ongoingOps);
5745
5746         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
5747                 active_vcp = vcp;
5748                 last_msg_time = GetCurrentTime();
5749         }
5750         else if (active_vcp == vcp)
5751                 active_vcp = NULL;
5752
5753     return;
5754 }
5755
5756 #ifndef DJGPP
5757 /* Wait for Netbios() calls to return, and make the results available to server
5758  * threads.  Note that server threads can't wait on the NCBevents array
5759  * themselves, because NCB events are manual-reset, and the servers would race
5760  * each other to reset them.
5761  */
5762 void smb_ClientWaiter(void *parmp)
5763 {
5764         DWORD code;
5765     int   idx;
5766
5767         while (1) {
5768                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
5769                                               FALSE, INFINITE);
5770                 if (code == WAIT_OBJECT_0)
5771                         continue;
5772
5773         /* error checking */
5774         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5775         {
5776             int abandonIdx = code - WAIT_ABANDONED_0;
5777             afsi_log("Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5778         }
5779
5780         if (code == WAIT_IO_COMPLETION)
5781         {
5782             afsi_log("Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
5783             continue;
5784         }
5785         
5786         if (code == WAIT_TIMEOUT)
5787         {
5788             afsi_log("Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
5789         }
5790
5791         if (code == WAIT_FAILED)
5792         {
5793             afsi_log("Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
5794         }
5795
5796         idx = code - WAIT_OBJECT_0;
5797  
5798         /* check idx range! */
5799         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
5800         {
5801             /* this is fatal - log as much as possible */
5802             afsi_log("Fatal: NCBevents idx [ %d ] out of range.\n", idx);
5803             osi_assert(0);
5804         }
5805         
5806                 thrd_ResetEvent(NCBevents[idx]);
5807                 thrd_SetEvent(NCBreturns[0][idx]);
5808         }
5809 }
5810 #endif /* !DJGPP */
5811
5812 /*
5813  * Try to have one NCBRECV request waiting for every live session.  Not more
5814  * than one, because if there is more than one, it's hard to handle Write Raw.
5815  */
5816 void smb_ServerWaiter(void *parmp)
5817 {
5818         DWORD code;
5819     int idx_session, idx_NCB;
5820         NCB *ncbp;
5821 #ifdef DJGPP
5822     dos_ptr dos_ncb;
5823 #endif /* DJGPP */
5824
5825         while (1) {
5826                 /* Get a session */
5827                 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
5828                                                    FALSE, INFINITE);
5829                 if (code == WAIT_OBJECT_0)
5830                         continue;
5831
5832         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
5833         {
5834             int abandonIdx = code - WAIT_ABANDONED_0;
5835             afsi_log("Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5836         }
5837         
5838         if (code == WAIT_IO_COMPLETION)
5839         {
5840             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
5841             continue;
5842         }
5843         
5844         if (code == WAIT_TIMEOUT)
5845         {
5846             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
5847         }
5848         
5849         if (code == WAIT_FAILED)
5850         {
5851             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
5852         }
5853         
5854         idx_session = code - WAIT_OBJECT_0;
5855
5856         /* check idx range! */
5857         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
5858         {
5859             /* this is fatal - log as much as possible */
5860             afsi_log("Fatal: session idx [ %d ] out of range.\n", idx_session);
5861             osi_assert(0);
5862         }
5863
5864                 /* Get an NCB */
5865       NCBretry:
5866                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
5867                                                    FALSE, INFINITE);
5868                 if (code == WAIT_OBJECT_0)
5869                         goto NCBretry;
5870
5871         /* error checking */
5872         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5873         {
5874             int abandonIdx = code - WAIT_ABANDONED_0;
5875             afsi_log("Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5876         }
5877         
5878         if (code == WAIT_IO_COMPLETION)
5879         {
5880             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
5881             continue;
5882         }
5883         
5884         if (code == WAIT_TIMEOUT)
5885         {
5886             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
5887         }
5888         
5889         if (code == WAIT_FAILED)
5890         {
5891             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
5892         }
5893                 
5894         idx_NCB = code - WAIT_OBJECT_0;
5895
5896         /* check idx range! */
5897         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
5898         {
5899             /* this is fatal - log as much as possible */
5900             afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
5901             osi_assert(0);
5902         }
5903
5904                 /* Link them together */
5905                 NCBsessions[idx_NCB] = idx_session;
5906
5907                 /* Fire it up */
5908                 ncbp = NCBs[idx_NCB];
5909 #ifdef DJGPP
5910         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
5911 #endif /* DJGPP */
5912                 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
5913                 ncbp->ncb_command = NCBRECV | ASYNCH;
5914                 ncbp->ncb_lana_num = lanas[idx_session];
5915 #ifndef DJGPP
5916                 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
5917                 ncbp->ncb_event = NCBevents[idx_NCB];
5918                 ncbp->ncb_length = SMB_PACKETSIZE;
5919                 Netbios(ncbp);
5920 #else /* DJGPP */
5921                 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
5922                 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
5923                 ncbp->ncb_event = NCBreturns[0][idx_NCB];
5924                 ncbp->ncb_length = SMB_PACKETSIZE;
5925                 Netbios(ncbp, dos_ncb);
5926 #endif /* !DJGPP */
5927         }
5928 }
5929
5930 /*
5931  * The top level loop for handling SMB request messages.  Each server thread
5932  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
5933  * NCB and buffer for the incoming request are loaned to us.
5934  *
5935  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
5936  * to immediately send a request for the rest of the data.  This must come
5937  * before any other traffic for that session, so we delay setting the session
5938  * event until that data has come in.
5939  */
5940 void smb_Server(VOID *parmp)
5941 {
5942         int myIdx = (int) parmp;
5943         NCB *ncbp;
5944         NCB *outncbp;
5945     smb_packet_t *bufp;
5946         smb_packet_t *outbufp;
5947     DWORD code, rcode;
5948     int idx_NCB, idx_session;
5949         UCHAR rc;
5950         smb_vc_t *vcp;
5951         smb_t *smbp;
5952 #ifdef DJGPP
5953     dos_ptr dos_ncb;
5954 #endif /* DJGPP */
5955
5956         outncbp = GetNCB();
5957         outbufp = GetPacket();
5958         outbufp->ncbp = outncbp;
5959
5960         while (1) {
5961 #ifndef NOEXPIRE
5962                 /* check for demo expiration */
5963                 {
5964                         unsigned long tod = time((void *) 0);
5965                         if (tod > EXPIREDATE) {
5966                                 (*smb_MBfunc)(NULL, "AFS demo expiration",
5967                                            "afsd dispatcher",
5968                                            MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
5969                                 trhd_Exit(1);
5970                         }
5971                 }
5972 #endif /* !NOEXPIRE */
5973
5974                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
5975                                                    FALSE, INFINITE);
5976                 if (code == WAIT_OBJECT_0) {
5977                         continue;
5978         }
5979
5980         /* error checking */
5981         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5982         {
5983             int abandonIdx = code - WAIT_ABANDONED_0;
5984             afsi_log("Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
5985         }
5986         
5987         if (code == WAIT_IO_COMPLETION)
5988         {
5989             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
5990             continue;
5991         }
5992         
5993         if (code == WAIT_TIMEOUT)
5994         {
5995             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
5996         }
5997         
5998         if (code == WAIT_FAILED)
5999         {
6000             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6001         }
6002
6003         idx_NCB = code - WAIT_OBJECT_0;
6004         
6005         /* check idx range! */
6006         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6007         {
6008             /* this is fatal - log as much as possible */
6009             afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6010             osi_assert(0);
6011         }
6012
6013                 ncbp = NCBs[idx_NCB];
6014 #ifdef DJGPP
6015                 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6016 #endif /* DJGPP */
6017                 idx_session = NCBsessions[idx_NCB];
6018                 rc = ncbp->ncb_retcode;
6019
6020                 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6021                         osi_Log1(afsd_logp, "NCBRECV failure code %d", rc);
6022
6023                 switch (rc) {
6024                         case NRC_GOODRET: break;
6025
6026                         case NRC_PENDING:
6027                                 /* Can this happen? Or is it just my
6028                                  * UNIX paranoia? 
6029                  */
6030                                 continue;
6031
6032                         case NRC_SCLOSED:
6033                         case NRC_SNUMOUT:
6034                                 /* Client closed session */
6035                 if (reportSessionStartups) 
6036                 {
6037                     afsi_log("session [ %d ] closed", idx_session);
6038                 }
6039                                 dead_sessions[idx_session] = TRUE;
6040                                 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6041                                 /* Should also release vcp.  Also, would do
6042                                  * sanity check that all TID's are gone. 
6043                  *
6044                  * TODO: check if we could use LSNs[idx_session] instead, 
6045                  * also cleanup after dead vcp 
6046                  */
6047                 if (vcp) {
6048                     if (dead_vcp)
6049                         osi_Log1(afsd_logp,
6050                                   "dead_vcp already set, %x",
6051                                   dead_vcp);
6052                     if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6053                         osi_Log2(afsd_logp,
6054                                   "setting dead_vcp %x, user struct %x",
6055                                   vcp, vcp->usersp);
6056                         dead_vcp = vcp;
6057                         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6058                     }
6059                     if (vcp->justLoggedOut) {
6060                         loggedOut = 1;
6061                         loggedOutTime = vcp->logoffTime;
6062                         loggedOutName =
6063                             strdup(vcp->justLoggedOut->unp->name);
6064                         loggedOutUserp = vcp->justLoggedOut;
6065                         lock_ObtainWrite(&smb_rctLock);
6066                         loggedOutUserp->refCount++;
6067                         lock_ReleaseWrite(&smb_rctLock);
6068                     }
6069                 }
6070                                 goto doneWithNCB;
6071
6072                         case NRC_INCOMP:
6073                                 /* Treat as transient error */
6074                                 {
6075 #ifndef DJGPP
6076                                         EVENT_HANDLE h;
6077                                         char *ptbuf[1];
6078                                         char s[100];
6079
6080                                         osi_Log1(smb_logp, "dispatch smb recv failed, message incomplete, ncb_length %d",
6081                              ncbp->ncb_length);
6082                                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6083                                         sprintf(s, "SMB message incomplete, length %d",
6084                             ncbp->ncb_length);
6085                                         ptbuf[0] = s;
6086                                         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6087                                 1001, NULL, 1,
6088                                 ncbp->ncb_length, ptbuf,
6089                                 bufp);
6090                                         DeregisterEventSource(h);
6091 #else /* DJGPP */
6092                                         osi_Log1(smb_logp,
6093                               "dispatch smb recv failed, message incomplete, ncb_length %d",
6094                               ncbp->ncb_length);
6095                     osi_Log1(smb_logp,
6096                               "SMB message incomplete, "
6097                               "length %d", ncbp->ncb_length);
6098 #endif /* !DJGPP */
6099
6100                                         /*
6101                                          * We used to discard the packet.
6102                                          * Instead, try handling it normally.
6103                                          *
6104                      continue;
6105                                          */
6106                                         break;
6107                                 }
6108
6109                         default:
6110                                 /* A weird error code.  Log it, sleep, and
6111                                  * continue. */
6112                                 if (vcp->errorCount++ > 3) {
6113                     afsi_log("session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6114                                         dead_sessions[idx_session] = TRUE;
6115                 }
6116                                 else {
6117                                         thrd_Sleep(1000);
6118                                         thrd_SetEvent(SessionEvents[idx_session]);
6119                                 }
6120                                 continue;
6121                 }
6122
6123                 /* Success, so now dispatch on all the data in the packet */
6124
6125                 smb_concurrentCalls++;
6126                 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6127                         smb_maxObsConcurrentCalls = smb_concurrentCalls;
6128
6129                 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6130         /*
6131                 * If at this point vcp is NULL (implies that packet was invalid)
6132                 * then we are in big trouble. This means either :
6133                 *   a) we have the wrong NCB.
6134                 *   b) Netbios screwed up the call.
6135                 * Obviously this implies that 
6136                 *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
6137                 *   lanas[idx_session] != ncbp->ncb_lana_num )
6138                 * Either way, we can't do anything with this packet.
6139                 * Log, sleep and resume.
6140                 */
6141                 if(!vcp) {
6142                         HANDLE h;
6143                         char buf[1000];
6144                         char *ptbuf[1];
6145
6146                         sprintf(buf,
6147                                 "Bad vcp!! : "
6148                                 "LSNs[idx_session]=[%d],"
6149                                 "lanas[idx_session]=[%d],"
6150                                 "ncbp->ncb_lsn=[%d],"
6151                                 "ncbp->ncb_lana_num=[%d]",
6152                                 LSNs[idx_session],
6153                                 lanas[idx_session],
6154                                 ncbp->ncb_lsn,
6155                                 ncbp->ncb_lana_num);
6156
6157                         ptbuf[0] = buf;
6158
6159                         h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6160                         if(h) {
6161                                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6162                                 DeregisterEventSource(h);
6163                         }
6164
6165                         /* Also log in the trace log. */
6166                         osi_Log4(afsd_logp, "Server: BAD VCP!"
6167                                 "LSNs[idx_session]=[%d],"
6168                                 "lanas[idx_session]=[%d],"
6169                                 "ncbp->ncb_lsn=[%d],"
6170                                 "ncbp->ncb_lana_num=[%d]",
6171                                 LSNs[idx_session],
6172                                 lanas[idx_session],
6173                                 ncbp->ncb_lsn,
6174                                 ncbp->ncb_lana_num);
6175
6176                         /* thrd_Sleep(1000); Don't bother sleeping */
6177                         thrd_SetEvent(SessionEvents[idx_session]);
6178                         smb_concurrentCalls--;
6179                         continue;
6180                 }
6181
6182
6183                 vcp->errorCount = 0;
6184                 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6185 #ifdef DJGPP
6186                 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6187         /* copy whole packet to virtual memory */
6188         /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6189         "bufp=0x%x\n",
6190         bufp->dos_pkt / 16, bufp);*/
6191         fflush(stderr);
6192         dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6193 #endif /* DJGPP */
6194                 smbp = (smb_t *)bufp->data;
6195                 outbufp->flags = 0;
6196
6197 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6198         __try
6199         {
6200 #endif
6201                 if (smbp->com == 0x1d) {
6202                         /* Special handling for Write Raw */
6203                         raw_write_cont_t rwc;
6204                         EVENT_HANDLE rwevent;
6205             char eventName[MAX_PATH];
6206             
6207             smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6208                         if (rwc.code == 0) {
6209                                 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6210                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6211                     afsi_log("Event Object Already Exists: %s", eventName);
6212                                 ncbp->ncb_command = NCBRECV | ASYNCH;
6213                                 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6214                                 ncbp->ncb_lana_num = vcp->lana;
6215                                 ncbp->ncb_buffer = rwc.buf;
6216                                 ncbp->ncb_length = 65535;
6217                                 ncbp->ncb_event = rwevent;
6218 #ifndef DJGPP
6219                                 Netbios(ncbp);
6220 #else
6221                                 Netbios(ncbp, dos_ncb);
6222 #endif /* !DJGPP */
6223                                 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6224                                 thrd_CloseHandle(rwevent);
6225                         }
6226                         thrd_SetEvent(SessionEvents[idx_session]);
6227                         if (rwc.code == 0)
6228                                 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6229                 } else if (smbp->com == 0xa0) { 
6230             /* 
6231              * Serialize the handling for NT Transact 
6232              * (defect 11626)
6233              */
6234             smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6235                         thrd_SetEvent(SessionEvents[idx_session]);
6236         } else {
6237                         thrd_SetEvent(SessionEvents[idx_session]);
6238             /* TODO: what else needs to be serialized? */
6239                         smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6240                 }
6241 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6242         }
6243         __except( smb_ServerExceptionFilter() ) {
6244         }
6245 #endif
6246
6247                 smb_concurrentCalls--;
6248
6249 doneWithNCB:
6250                 thrd_SetEvent(NCBavails[idx_NCB]);
6251         }
6252 }
6253
6254 /*
6255  * Exception filter for the server threads.  If an exception occurs in the
6256  * dispatch routines, which is where exceptions are most common, then do a
6257  * force trace and give control to upstream exception handlers. Useful for
6258  * debugging.
6259  */
6260 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6261 DWORD smb_ServerExceptionFilter(void) {
6262         /* While this is not the best time to do a trace, if it succeeds, then
6263          * we have a trace (assuming tracing was enabled). Otherwise, this should
6264          * throw a second exception.
6265          */
6266         HANDLE h;
6267         char *ptbuf[1];
6268
6269         ptbuf[0] = "Unhandled exception forcing trace";
6270
6271         h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6272         if(h) {
6273                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6274                 DeregisterEventSource(h);
6275         }
6276
6277         afsd_ForceTrace(TRUE);
6278         return EXCEPTION_CONTINUE_SEARCH;
6279 }
6280 #endif
6281
6282 /*
6283  * Create a new NCB and associated events, packet buffer, and "space" buffer.
6284  * If the number of server threads is M, and the number of live sessions is
6285  * N, then the number of NCB's in use at any time either waiting for, or
6286  * holding, received messages is M + N, so that is how many NCB's get created.
6287  */
6288 void InitNCBslot(int idx)
6289 {
6290         struct smb_packet *bufp;
6291         EVENT_HANDLE retHandle;
6292         int i;
6293     char eventName[MAX_PATH];
6294
6295     osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6296
6297         NCBs[idx] = GetNCB();
6298     sprintf(eventName,"NCBavails[%d]", idx);
6299         NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6300     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6301         afsi_log("Event Object Already Exists: %s", eventName);
6302 #ifndef DJGPP
6303     sprintf(eventName,"NCBevents[%d]", idx);
6304         NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6305     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6306         afsi_log("Event Object Already Exists: %s", eventName);
6307 #endif /* !DJGPP */
6308     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6309         retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6310     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6311         afsi_log("Event Object Already Exists: %s", eventName);
6312         for (i=0; i<smb_NumServerThreads; i++)
6313                 NCBreturns[i][idx] = retHandle;
6314         bufp = GetPacket();
6315         bufp->spacep = cm_GetSpace();
6316         bufs[idx] = bufp;
6317 }
6318
6319 /* listen for new connections */
6320 void smb_Listener(void *parmp)
6321 {
6322         NCB *ncbp;
6323     long code;
6324     long len;
6325         long i, j;
6326     smb_vc_t *vcp;
6327         int flags = 0;
6328         char rname[NCBNAMSZ+1];
6329         char cname[MAX_COMPUTERNAME_LENGTH+1];
6330         int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6331 #ifdef DJGPP
6332     dos_ptr dos_ncb;
6333     time_t now;
6334 #endif /* DJGPP */
6335         int lana = (int) parmp;
6336
6337         ncbp = GetNCB();
6338 #ifdef DJGPP
6339     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6340 #endif /* DJGPP */
6341
6342     /* retrieve computer name */
6343     GetComputerName(cname, &cnamelen);
6344     _strupr(cname);
6345
6346         while (1) {
6347                 memset(ncbp, 0, sizeof(NCB));
6348                 flags = 0;
6349
6350 #ifndef NOEXPIRE
6351                 /* check for demo expiration */
6352                 {
6353                         unsigned long tod = time((void *) 0);
6354                         if (tod > EXPIREDATE) {
6355                                 (*smb_MBfunc)(NULL, "AFS demo expiration",
6356                                "afsd listener",
6357                                MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
6358 #ifndef DJGPP
6359                 ExitThread(1);
6360 #else
6361                 thrd_Exit(1);
6362 #endif
6363                         }
6364                 }
6365 #endif /* !NOEXPIRE */
6366
6367         ncbp->ncb_command = NCBLISTEN;
6368         ncbp->ncb_rto = 0;      /* No receive timeout */
6369         ncbp->ncb_sto = 0;      /* No send timeout */
6370
6371                 /* pad out with spaces instead of null termination */
6372                 len = strlen(smb_localNamep);
6373         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6374         for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6375         
6376         strcpy(ncbp->ncb_callname, "*");
6377         for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6378         
6379                 ncbp->ncb_lana_num = lana;
6380
6381 #ifndef DJGPP
6382         code = Netbios(ncbp);
6383 #else /* DJGPP */
6384         code = Netbios(ncbp, dos_ncb);
6385 #endif
6386
6387         if (code != 0)
6388         {
6389                     /* terminate if shutdown flag is set */
6390                 if (smbShutdownFlag == 1) {
6391 #ifndef DJGPP
6392                             ExitThread(1);
6393 #else
6394                                 thrd_Exit(1);
6395 #endif
6396                         }
6397
6398 #ifndef DJGPP
6399                         osi_assert(0);
6400 #else
6401             fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6402                      ncbp->ncb_lana_num, code);
6403             osi_Log2(0, "NCBLISTEN lana=%d failed with code %d",
6404                       ncbp->ncb_lana_num, code);
6405             fprintf(stderr, "\nClient exiting due to network failure "
6406                      "(possibly due to power-saving mode)\n");
6407             fprintf(stderr, "Please restart client.\n");
6408             afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6409 #endif /* !DJGPP */
6410         }
6411
6412                 /* check for remote conns */
6413                 /* first get remote name and insert null terminator */
6414                 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6415                 for (i=NCBNAMSZ; i>0; i--) {
6416                         if (rname[i-1] != ' ' && rname[i-1] != 0) {
6417                                 rname[i] = 0;
6418                                 break;
6419                         }
6420                 }
6421
6422         /* compare with local name */
6423                 if (!isGateway)
6424                         if (strncmp(rname, cname, NCBNAMSZ) != 0)
6425                                 flags |= SMB_VCFLAG_REMOTECONN;
6426
6427                 osi_Log1(afsd_logp, "New session lsn %d", ncbp->ncb_lsn);
6428                 /* lock */
6429                 lock_ObtainMutex(&smb_ListenerLock);
6430
6431                 /* New generation */
6432                 sessionGen++;
6433
6434                 /* Log session startup */
6435 #ifdef NOTSERVICE
6436         fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6437                                 "%s\n",
6438                 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6439 #endif
6440         afsi_log("New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6441                   ncbp->ncb_lsn,ncbp->ncb_lana_num, rname, ongoingOps);
6442
6443         if (reportSessionStartups) {
6444 #ifndef DJGPP
6445                         HANDLE h;
6446                         char *ptbuf[1];
6447                         char s[100];
6448
6449                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6450                         sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
6451                         ptbuf[0] = s;
6452                         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6453                         1, 0, ptbuf, NULL);
6454                         DeregisterEventSource(h);
6455 #else /* DJGPP */
6456             afsi_log("NCBLISTEN completed, call from %s",rname);
6457             osi_Log1(afsd_logp, "SMB session startup, %d ongoing ops",
6458                      ongoingOps);
6459             time(&now);
6460             fprintf(stderr, "%s: New session %d starting from host %s\n",
6461                     asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6462             fflush(stderr);
6463 #endif /* !DJGPP */
6464                 }
6465
6466         /* now ncbp->ncb_lsn is the connection ID */
6467         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6468                 vcp->flags |= flags;
6469         strcpy(vcp->rname, rname);
6470
6471                 /* Allocate slot in session arrays */
6472                 /* Re-use dead session if possible, otherwise add one more */
6473         /* But don't look at session[0], it is reserved */
6474                 for (i = 1; i < numSessions; i++) {
6475                         if (dead_sessions[i]) {
6476                 afsi_log("connecting to dead session [ %d ]", i);
6477                                 dead_sessions[i] = FALSE;
6478                                 break;
6479                         }
6480                 }
6481
6482         /* assert that we do not exceed the maximum number of sessions or NCBs.
6483          * we should probably want to wait for a session to be freed in case
6484          * we run out.
6485          */
6486
6487         osi_assert(i < Sessionmax && numNCBs < NCBmax - 1);
6488
6489                 LSNs[i] = ncbp->ncb_lsn;
6490                 lanas[i] = ncbp->ncb_lana_num;
6491                 
6492                 if (i == numSessions) {
6493                         /* Add new NCB for new session */
6494             char eventName[MAX_PATH];
6495
6496             osi_Log1(afsd_logp, "smb_Listener creating new session %d", i);
6497
6498                         InitNCBslot(numNCBs);
6499                         numNCBs++;
6500                         thrd_SetEvent(NCBavails[0]);
6501                         thrd_SetEvent(NCBevents[0]);
6502                         for (j = 0; j < smb_NumServerThreads; j++)
6503                                 thrd_SetEvent(NCBreturns[j][0]);
6504                         /* Also add new session event */
6505             sprintf(eventName, "SessionEvents[%d]", i);
6506             SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6507             if ( GetLastError() == ERROR_ALREADY_EXISTS )
6508                 afsi_log("Event Object Already Exists: %s", eventName);
6509                         numSessions++;
6510             afsi_log("increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
6511                         thrd_SetEvent(SessionEvents[0]);
6512                 } else {
6513                         thrd_SetEvent(SessionEvents[i]);
6514                 }
6515                 /* unlock */
6516                 lock_ReleaseMutex(&smb_ListenerLock);
6517
6518     }   /* dispatch while loop */
6519 }
6520
6521 /* initialize Netbios */
6522 void smb_NetbiosInit()
6523 {
6524     NCB *ncbp;
6525 #ifdef DJGPP
6526     dos_ptr dos_ncb;
6527 #endif /* DJGPP */
6528     int i, lana, code, l;
6529     char s[100];
6530     int delname_tried=0;
6531     int len;
6532     int lana_found = 0;
6533     OSVERSIONINFO Version;
6534
6535     /* AFAIK, this is the default for the ms loopback adapter.*/
6536     unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
6537     /*******************************************************************/
6538
6539     /* Get the version of Windows */
6540     memset(&Version, 0x00, sizeof(Version));
6541     Version.dwOSVersionInfoSize = sizeof(Version);
6542     GetVersionEx(&Version);
6543
6544     /* setup the NCB system */
6545     ncbp = GetNCB();
6546 #ifdef DJGPP
6547     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6548 #endif /* DJGPP */
6549
6550 #ifndef DJGPP
6551     if (smb_LANadapter == -1) {
6552         ncbp->ncb_command = NCBENUM;
6553         ncbp->ncb_buffer = (PUCHAR)&lana_list;
6554         ncbp->ncb_length = sizeof(lana_list);
6555         code = Netbios(ncbp);
6556         if (code != 0) {
6557             sprintf(s, "Netbios NCBENUM error code %d", code);
6558             afsi_log(s);
6559             osi_panic(s, __FILE__, __LINE__);
6560         }
6561     }
6562     else {
6563         lana_list.length = 1;
6564         lana_list.lana[0] = smb_LANadapter;
6565     }
6566           
6567     for (i = 0; i < lana_list.length; i++) {
6568         /* reset the adaptor: in Win32, this is required for every process, and
6569          * acts as an init call, not as a real hardware reset.
6570          */
6571         ncbp->ncb_command = NCBRESET;
6572         ncbp->ncb_callname[0] = 100;
6573         ncbp->ncb_callname[2] = 100;
6574         ncbp->ncb_lana_num = lana_list.lana[i];
6575         code = Netbios(ncbp);
6576         if (code == 0) 
6577             code = ncbp->ncb_retcode;
6578         if (code != 0) {
6579             sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
6580             afsi_log(s);
6581             lana_list.lana[i] = 255;  /* invalid lana */
6582         } else {
6583             sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
6584             afsi_log(s);
6585         }
6586     }
6587 #else
6588     /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset.  so
6589        we will just fake the LANA list */
6590     if (smb_LANadapter == -1) {
6591         for (i = 0; i < 8; i++)
6592             lana_list.lana[i] = i;
6593         lana_list.length = 8;
6594     }
6595     else {
6596         lana_list.length = 1;
6597         lana_list.lana[0] = smb_LANadapter;
6598     }
6599 #endif /* !DJGPP */
6600
6601     /* and declare our name so we can receive connections */
6602     memset(ncbp, 0, sizeof(*ncbp));
6603     len=lstrlen(smb_localNamep);
6604     memset(smb_sharename,' ',NCBNAMSZ);
6605     memcpy(smb_sharename,smb_localNamep,len);
6606     sprintf(s, "lana_list.length %d", lana_list.length);
6607     afsi_log(s);
6608
6609     /* Keep the name so we can unregister it later */
6610     for (l = 0; l < lana_list.length; l++) {
6611         lana = lana_list.lana[l];
6612
6613         ncbp->ncb_command = NCBADDNAME;
6614         ncbp->ncb_lana_num = lana;
6615         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6616 #ifndef DJGPP
6617         code = Netbios(ncbp);
6618 #else /* DJGPP */
6619         code = Netbios(ncbp, dos_ncb);
6620 #endif /* !DJGPP */
6621           
6622         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
6623                  lana, code, ncbp->ncb_retcode,ncbp->ncb_cmd_cplt);
6624         {
6625             char name[NCBNAMSZ+1];
6626             name[NCBNAMSZ]=0;
6627             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
6628             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
6629         }
6630
6631         if (code == 0) code = ncbp->ncb_retcode;
6632         if (code == 0) {
6633             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
6634 #ifdef DJGPP
6635             /* we only use one LANA with djgpp */
6636             lana_list.lana[0] = lana;
6637             lana_list.length = 1;
6638 #endif    
6639         }
6640         else {
6641             sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6642             afsi_log(s);
6643             if (code == NRC_BRIDGE) {    /* invalid LANA num */
6644                 lana_list.lana[l] = 255;
6645                 continue;
6646             }
6647             else if (code == NRC_DUPNAME) {
6648                 afsi_log("Name already exists; try to delete it");
6649                 memset(ncbp, 0, sizeof(*ncbp));
6650                 ncbp->ncb_command = NCBDELNAME;
6651                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6652                 ncbp->ncb_lana_num = lana;
6653 #ifndef DJGPP
6654                 code = Netbios(ncbp);
6655 #else
6656                 code = Netbios(ncbp, dos_ncb);
6657 #endif /* DJGPP */
6658                 if (code == 0) code = ncbp->ncb_retcode;
6659                 else {
6660                     sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
6661                     afsi_log(s);
6662                 }
6663                 if (code != 0 || delname_tried) {
6664                     lana_list.lana[l] = 255;
6665                 }
6666                 else if (code == 0) {
6667                     if (!delname_tried) {
6668                         lana--;
6669                         delname_tried = 1;
6670                         continue;
6671                     }
6672                 }
6673             }
6674             else {
6675                 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6676                 afsi_log(s);
6677                 lana_list.lana[l] = 255;  /* invalid lana */
6678                 osi_panic(s, __FILE__, __LINE__);
6679             }
6680         }
6681         if (code == 0) {
6682             lana_found = 1;   /* at least one worked */
6683 #ifdef DJGPP
6684             break;
6685 #endif
6686         }
6687     }
6688
6689     osi_assert(lana_list.length >= 0);
6690     if (!lana_found) {
6691         sprintf(s, "No valid LANA numbers found!");
6692         osi_panic(s, __FILE__, __LINE__);
6693     }
6694         
6695     /* we're done with the NCB now */
6696     FreeNCB(ncbp);
6697 }
6698
6699 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
6700               int nThreads
6701 #ifndef DJGPP
6702               , void *aMBfunc
6703 #endif
6704   )
6705
6706 {
6707         thread_t phandle;
6708     int lpid;
6709     int i;
6710     int len;
6711         struct tm myTime;
6712 #ifdef DJGPP
6713     int npar, seg, sel;
6714     dos_ptr rawBuf;
6715 #endif /* DJGPP */
6716     EVENT_HANDLE retHandle;
6717     char eventName[MAX_PATH];
6718
6719 #ifndef DJGPP
6720         smb_MBfunc = aMBfunc;
6721 #endif /* DJGPP */
6722
6723 #ifndef NOEXPIRE
6724         /* check for demo expiration */
6725         {
6726                 unsigned long tod = time((void *) 0);
6727                 if (tod > EXPIREDATE) {
6728 #ifndef DJGPP
6729                         (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
6730                           MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
6731                         exit(1);
6732 #else /* DJGPP */
6733             fprintf(stderr, "AFS demo expiration\n");
6734             afs_exit(0);
6735 #endif /* !DJGPP */
6736                 }
6737         }
6738 #endif /* !NOEXPIRE */
6739
6740         smb_useV3 = useV3;
6741         smb_LANadapter = LANadapt;
6742
6743         /* Initialize smb_localZero */
6744         myTime.tm_isdst = -1;           /* compute whether on DST or not */
6745         myTime.tm_year = 70;
6746         myTime.tm_mon = 0;
6747         myTime.tm_mday = 1;
6748         myTime.tm_hour = 0;
6749         myTime.tm_min = 0;
6750         myTime.tm_sec = 0;
6751         smb_localZero = mktime(&myTime);
6752
6753         /* Initialize kludge-GMT */
6754         smb_CalculateNowTZ();
6755
6756         /* initialize the remote debugging log */
6757         smb_logp = logp;
6758         
6759     /* remember the name */
6760         len = strlen(snamep);
6761     smb_localNamep = malloc(len+1);
6762     strcpy(smb_localNamep, snamep);
6763     afsi_log("smb_localNamep is >%s<", smb_localNamep);
6764
6765         /* and the global lock */
6766     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
6767     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
6768
6769         /* Raw I/O data structures */
6770         lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
6771
6772         lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
6773         
6774         /* 4 Raw I/O buffers */
6775 #ifndef DJGPP
6776         smb_RawBufs = calloc(65536,1);
6777         *((char **)smb_RawBufs) = NULL;
6778         for (i=0; i<3; i++) {
6779                 char *rawBuf = calloc(65536,1);
6780                 *((char **)rawBuf) = smb_RawBufs;
6781                 smb_RawBufs = rawBuf;
6782         }
6783 #else /* DJGPP */
6784     npar = 65536 >> 4;  /* number of paragraphs */
6785     seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
6786     if (seg == -1) {
6787         afsi_log("Cannot allocate %d paragraphs of DOS memory",
6788                   npar);
6789         osi_panic("",__FILE__,__LINE__);
6790     }
6791     else {
6792         afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
6793                   npar, seg);
6794     }
6795     smb_RawBufs = (seg * 16) + 0;  /* DOS physical address */
6796         
6797     _farpokel(_dos_ds, smb_RawBufs, NULL);
6798     for (i=0; i<SMB_RAW_BUFS-1; i++) {
6799         npar = 65536 >> 4;  /* number of paragraphs */
6800         seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
6801         if (seg == -1) {
6802             afsi_log("Cannot allocate %d paragraphs of DOS memory",
6803                       npar);
6804             osi_panic("",__FILE__,__LINE__);
6805         }
6806         else {
6807             afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
6808                       npar, seg);
6809         }
6810         rawBuf = (seg * 16) + 0;  /* DOS physical address */
6811         /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
6812         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6813         smb_RawBufs = rawBuf;
6814     }
6815 #endif /* !DJGPP */
6816
6817         /* global free lists */
6818         smb_ncbFreeListp = NULL;
6819     smb_packetFreeListp = NULL;
6820
6821     smb_NetbiosInit();
6822
6823         /* Initialize listener and server structures */
6824         memset(dead_sessions, 0, sizeof(dead_sessions));
6825     sprintf(eventName, "SessionEvents[0]");
6826         SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6827     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6828         afsi_log("Event Object Already Exists: %s", eventName);
6829         numSessions = 1;
6830         smb_NumServerThreads = nThreads;
6831     sprintf(eventName, "NCBavails[0]");
6832         NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6833     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6834         afsi_log("Event Object Already Exists: %s", eventName);
6835     sprintf(eventName, "NCBevents[0]");
6836         NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6837     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6838         afsi_log("Event Object Already Exists: %s", eventName);
6839         NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
6840     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
6841     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6842     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6843         afsi_log("Event Object Already Exists: %s", eventName);
6844         for (i = 0; i < smb_NumServerThreads; i++) {
6845                 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
6846                 NCBreturns[i][0] = retHandle;
6847         }
6848         for (i = 1; i <= nThreads; i++)
6849                 InitNCBslot(i);
6850         numNCBs = nThreads + 1;
6851
6852         /* Initialize dispatch table */
6853         memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
6854         smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
6855         smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
6856         smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
6857         smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
6858         smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
6859         smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
6860         smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
6861         smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
6862         smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
6863         smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
6864         smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
6865         smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
6866         smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
6867         smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
6868         smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
6869         smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
6870         smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
6871         smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;      /* process exit */
6872         smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
6873         smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
6874         /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
6875         smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6876         smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
6877         smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
6878         smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
6879         smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
6880         smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
6881         smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;      /* copy file */
6882         smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
6883         /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
6884         smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6885     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
6886     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
6887     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
6888     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
6889         smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;    /* both are same */
6890     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6891     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
6892     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6893     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
6894     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
6895         smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
6896         smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
6897         smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
6898         smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
6899     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
6900     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
6901     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
6902     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
6903     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
6904         smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
6905         smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
6906         smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
6907         smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
6908         smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
6909         smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
6910         smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6911         smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
6912         smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
6913         smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
6914         smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
6915         for(i=0xd0; i<= 0xd7; i++) {
6916                 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
6917     }
6918
6919         /* setup tran 2 dispatch table */
6920         smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
6921         smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;    /* FindFirst */
6922         smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;    /* FindNext */
6923         smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
6924         smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
6925         smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
6926         smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
6927         smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
6928         smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
6929         smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
6930         smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
6931         smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
6932         smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
6933         smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
6934
6935         smb3_Init();
6936
6937         /* Start listeners, waiters, servers, and daemons */
6938
6939         for (i = 0; i < lana_list.length; i++) {
6940                 if (lana_list.lana[i] == 255) continue;
6941                 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
6942                         (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
6943                 osi_assert(phandle != NULL);
6944                 thrd_CloseHandle(phandle);
6945         }
6946
6947 #ifndef DJGPP
6948     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
6949                           NULL, 0, &lpid, "smb_ClientWaiter");
6950         osi_assert(phandle != NULL);
6951         thrd_CloseHandle(phandle);
6952 #endif /* !DJGPP */
6953
6954     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
6955                           NULL, 0, &lpid, "smb_ServerWaiter");
6956         osi_assert(phandle != NULL);
6957         thrd_CloseHandle(phandle);
6958
6959         for (i=0; i<nThreads; i++) {
6960                 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
6961                               (void *) i, 0, &lpid, "smb_Server");
6962                 osi_assert(phandle != NULL);
6963                 thrd_CloseHandle(phandle);
6964         }
6965
6966     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
6967                           NULL, 0, &lpid, "smb_Daemon");
6968         osi_assert(phandle != NULL);
6969         thrd_CloseHandle(phandle);
6970
6971         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
6972                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
6973         osi_assert(phandle != NULL);
6974         thrd_CloseHandle(phandle);
6975
6976 #ifdef DJGPP
6977         smb_ListShares();
6978 #endif
6979
6980         return;
6981 }
6982
6983 void smb_Shutdown(void)
6984 {
6985     NCB *ncbp;
6986 #ifdef DJGPP
6987     dos_ptr dos_ncb;
6988 #endif
6989     long code;
6990     int i;
6991
6992     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
6993         
6994     /* setup the NCB system */
6995     ncbp = GetNCB();
6996 #ifdef DJGPP
6997     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6998 #endif
6999
7000     /* Block new sessions by setting shutdown flag */
7001     smbShutdownFlag = 1;
7002
7003     /* Hang up all sessions */
7004     memset((char *)ncbp, 0, sizeof(NCB));
7005     for (i = 1; i < numSessions; i++)
7006     {
7007         if (dead_sessions[i])
7008             continue;
7009       
7010         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7011         ncbp->ncb_command = NCBHANGUP;
7012         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
7013         ncbp->ncb_lsn = LSNs[i];
7014 #ifndef DJGPP
7015         code = Netbios(ncbp);
7016 #else
7017                 code = Netbios(ncbp, dos_ncb);
7018 #endif
7019         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7020         if (code == 0) code = ncbp->ncb_retcode;
7021         if (code != 0) {
7022             osi_Log1(afsd_logp, "Netbios NCBHANGUP error code %d", code);
7023             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7024         }
7025     }
7026
7027     /* Delete Netbios name */
7028     memset((char *)ncbp, 0, sizeof(NCB));
7029         for (i = 0; i < lana_list.length; i++) {
7030                 if (lana_list.lana[i] == 255) continue;
7031                 ncbp->ncb_command = NCBDELNAME;
7032                 ncbp->ncb_lana_num = lana_list.lana[i];
7033                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7034 #ifndef DJGPP
7035         code = Netbios(ncbp);
7036 #else
7037                 code = Netbios(ncbp, dos_ncb);
7038 #endif
7039                 if (code == 0) code = ncbp->ncb_retcode;
7040                 if (code != 0) {
7041                         fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7042                         ncbp->ncb_lana_num, code);
7043                 }
7044                 fflush(stderr);
7045         }
7046 }
7047
7048 /* Get the UNC \\<servername>\<sharename> prefix. */
7049 char *smb_GetSharename()
7050 {
7051     char *name;
7052
7053         /* Make sure we have been properly initialized. */
7054         if (smb_localNamep == NULL)
7055                 return NULL;
7056
7057     /* Allocate space for \\<servername>\<sharename>, plus the
7058      * terminator.
7059      */
7060     name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7061     sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7062     return name;
7063 }   
7064
7065 #ifdef NOTSERVICE
7066
7067 void smb_LogPacket(smb_packet_t *packet)
7068 {
7069         BYTE *vp, *cp;
7070         unsigned length, paramlen, datalen, i, j;
7071         char buf[81];
7072         char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7073
7074         if(!packet) return;
7075
7076         osi_Log0(afsd_logp, "*** SMB packet dump ***");
7077
7078         vp = (BYTE *) packet->data;
7079
7080         datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7081         length = paramlen + 2 + datalen;
7082
7083
7084         for(i=0;i < length; i+=16)
7085         {
7086                 memset( buf, ' ', 80 );
7087                 buf[80] = 0;
7088
7089                 itoa( i, buf, 16 );
7090
7091                 buf[strlen(buf)] = ' ';
7092
7093                 cp = (BYTE*) buf + 7;
7094
7095                 for(j=0;j < 16 && (i+j)<length; j++)
7096                 {
7097                         *(cp++) = hex[vp[i+j] >> 4];
7098                         *(cp++) = hex[vp[i+j] & 0xf];
7099                         *(cp++) = ' ';
7100
7101                         if(j==7)
7102                         {
7103                                 *(cp++) = '-';
7104                                 *(cp++) = ' ';
7105                         }
7106                 }
7107
7108                 for(j=0;j < 16 && (i+j)<length;j++)
7109                 {
7110                         *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7111                         if(j==7)
7112                         {
7113                                 *(cp++) = ' ';
7114                                 *(cp++) = '-';
7115                                 *(cp++) = ' ';
7116                         }
7117                 }
7118
7119                 *cp = 0;
7120
7121                 osi_Log0( afsd_logp, buf );
7122         }
7123
7124         osi_Log0(afsd_logp, "*** End SMB packet dump ***");
7125
7126 }
7127
7128 #endif /* NOTSERVICE */
7129
7130 int smb_DumpVCP(FILE *outputFile, char *cookie)
7131 {
7132     int zilch;
7133     char output[1024];
7134   
7135     smb_vc_t *vcp;
7136   
7137     lock_ObtainRead(&smb_rctLock);
7138   
7139     for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
7140     {
7141         smb_fid_t *fidp;
7142       
7143         sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7144                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7145         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7146       
7147         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) 
7148         {
7149             sprintf(output, "%s -- fidp=0x%08X, refCount=%d, fid=%d, vcp=0x%08X, scp=0x%08X, ioctlp=0x%08X, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
7150                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
7151                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
7152                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7153             WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7154         }
7155       
7156         sprintf(output, "done dumping fidsp\n");
7157         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7158     }       
7159   
7160     lock_ReleaseRead(&smb_rctLock);
7161     return 0;
7162 }