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