local.h: Fix spelling mistake :-).
[kai/samba.git] / source3 / smbd / trans2.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB transaction2 handling
5    Copyright (C) Jeremy Allison 1994-1997
6
7    Extensively modified by Andrew Tridgell, 1995
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "trans2.h"
26
27 extern int DEBUGLEVEL;
28 extern int Protocol;
29 extern connection_struct Connections[];
30 extern files_struct Files[];
31 extern BOOL case_sensitive;
32 extern int Client;
33
34 /****************************************************************************
35   Send the required number of replies back.
36   We assume all fields other than the data fields are
37   set correctly for the type of call.
38   HACK ! Always assumes smb_setup field is zero.
39 ****************************************************************************/
40 static int send_trans2_replies(char *outbuf, int bufsize, char *params, 
41                          int paramsize, char *pdata, int datasize)
42 {
43   /* As we are using a protocol > LANMAN1 then the max_send
44      variable must have been set in the sessetupX call.
45      This takes precedence over the max_xmit field in the
46      global struct. These different max_xmit variables should
47      be merged as this is now too confusing */
48
49   extern int max_send;
50   int data_to_send = datasize;
51   int params_to_send = paramsize;
52   int useable_space;
53   char *pp = params;
54   char *pd = pdata;
55   int params_sent_thistime, data_sent_thistime, total_sent_thistime;
56   int alignment_offset = 1;
57
58   /* Initially set the wcnt area to be 10 - this is true for all
59      trans2 replies */
60   set_message(outbuf,10,0,True);
61
62   /* If there genuinely are no parameters or data to send just send
63      the empty packet */
64   if(params_to_send == 0 && data_to_send == 0)
65     {
66       send_smb(Client,outbuf);
67       return 0;
68     }
69
70   /* Space is bufsize minus Netbios over TCP header minus SMB header */
71   /* The alignment_offset is to align the param and data bytes on an even byte
72      boundary. NT 4.0 Beta needs this to work correctly. */
73   useable_space = bufsize - ((smb_buf(outbuf)+alignment_offset) - outbuf);
74   /* useable_space can never be more than max_send minus the
75      alignment offset. */
76   useable_space = MIN(useable_space, max_send - alignment_offset);
77
78   while( params_to_send || data_to_send)
79     {
80       /* Calculate whether we will totally or partially fill this packet */
81       total_sent_thistime = params_to_send + data_to_send + alignment_offset;
82       /* We can never send more than useable_space */
83       total_sent_thistime = MIN(total_sent_thistime, useable_space);
84
85       set_message(outbuf, 10, total_sent_thistime, True);
86
87       /* Set total params and data to be sent */
88       SSVAL(outbuf,smb_tprcnt,paramsize);
89       SSVAL(outbuf,smb_tdrcnt,datasize);
90
91       /* Calculate how many parameters and data we can fit into
92          this packet. Parameters get precedence */
93
94       params_sent_thistime = MIN(params_to_send,useable_space);
95       data_sent_thistime = useable_space - params_sent_thistime;
96       data_sent_thistime = MIN(data_sent_thistime,data_to_send);
97
98       SSVAL(outbuf,smb_prcnt, params_sent_thistime);
99       if(params_sent_thistime == 0)
100         {
101           SSVAL(outbuf,smb_proff,0);
102           SSVAL(outbuf,smb_prdisp,0);
103         } else {
104           /* smb_proff is the offset from the start of the SMB header to the
105              parameter bytes, however the first 4 bytes of outbuf are
106              the Netbios over TCP header. Thus use smb_base() to subtract
107              them from the calculation */
108           SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
109           /* Absolute displacement of param bytes sent in this packet */
110           SSVAL(outbuf,smb_prdisp,pp - params);
111         }
112
113       SSVAL(outbuf,smb_drcnt, data_sent_thistime);
114       if(data_sent_thistime == 0)
115         {
116           SSVAL(outbuf,smb_droff,0);
117           SSVAL(outbuf,smb_drdisp, 0);
118         } else {
119           /* The offset of the data bytes is the offset of the
120              parameter bytes plus the number of parameters being sent this time */
121           SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - 
122                                   smb_base(outbuf)) + params_sent_thistime);
123           SSVAL(outbuf,smb_drdisp, pd - pdata);
124         }
125
126       /* Copy the param bytes into the packet */
127       if(params_sent_thistime)
128         memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
129       /* Copy in the data bytes */
130       if(data_sent_thistime)
131         memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime,pd,data_sent_thistime);
132
133       DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
134                params_sent_thistime, data_sent_thistime, useable_space));
135       DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
136                params_to_send, data_to_send, paramsize, datasize));
137
138       /* Send the packet */
139       send_smb(Client,outbuf);
140
141       pp += params_sent_thistime;
142       pd += data_sent_thistime;
143
144       params_to_send -= params_sent_thistime;
145       data_to_send -= data_sent_thistime;
146
147       /* Sanity check */
148       if(params_to_send < 0 || data_to_send < 0)
149         {
150           DEBUG(2,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
151                    params_to_send, data_to_send));
152           return -1;
153         }
154     }
155
156   return 0;
157 }
158
159
160 /****************************************************************************
161   reply to a TRANSACT2_OPEN
162 ****************************************************************************/
163 static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum, 
164                     char **pparams, char **ppdata)
165 {
166   char *params = *pparams;
167   int16 open_mode = SVAL(params, 2);
168   int16 open_attr = SVAL(params,6);
169   BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1));
170 #if 0
171   BOOL return_additional_info = BITSETW(params,0);
172   int16 open_sattr = SVAL(params, 4);
173   time_t open_time = make_unix_date3(params+8);
174 #endif
175   int16 open_ofun = SVAL(params,12);
176   int32 open_size = IVAL(params,14);
177   char *pname = &params[28];
178   int16 namelen = strlen(pname)+1;
179
180   pstring fname;
181   int fnum = -1;
182   int unixmode;
183   int size=0,fmode=0,mtime=0,rmode;
184   int32 inode = 0;
185   struct stat sbuf;
186   int smb_action = 0;
187   BOOL bad_path = False;
188
189   StrnCpy(fname,pname,namelen);
190
191   DEBUG(3,("trans2open %s cnum=%d mode=%d attr=%d ofun=%d size=%d\n",
192            fname,cnum,open_mode, open_attr, open_ofun, open_size));
193
194   /* XXXX we need to handle passed times, sattr and flags */
195
196   unix_convert(fname,cnum,0,&bad_path);
197     
198   fnum = find_free_file();
199   if (fnum < 0)
200     return(ERROR(ERRSRV,ERRnofids));
201
202   if (!check_name(fname,cnum))
203   {
204     if((errno == ENOENT) && bad_path)
205     {
206       unix_ERR_class = ERRDOS;
207       unix_ERR_code = ERRbadpath;
208     }
209     return(UNIXERROR(ERRDOS,ERRnoaccess));
210   }
211
212   unixmode = unix_mode(cnum,open_attr | aARCH);
213       
214       
215   open_file_shared(fnum,cnum,fname,open_mode,open_ofun,unixmode,
216                    oplock_request, &rmode,&smb_action);
217       
218   if (!Files[fnum].open)
219   {
220     if((errno == ENOENT) && bad_path)
221     {
222       unix_ERR_class = ERRDOS;
223       unix_ERR_code = ERRbadpath;
224     }
225     return(UNIXERROR(ERRDOS,ERRnoaccess));
226   }
227
228   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
229     close_file(fnum);
230     return(ERROR(ERRDOS,ERRnoaccess));
231   }
232     
233   size = sbuf.st_size;
234   fmode = dos_mode(cnum,fname,&sbuf);
235   mtime = sbuf.st_mtime;
236   inode = sbuf.st_ino;
237   if (fmode & aDIR) {
238     close_file(fnum);
239     return(ERROR(ERRDOS,ERRnoaccess));
240   }
241
242   /* Realloc the size of parameters and data we will return */
243   params = *pparams = Realloc(*pparams, 28);
244   if(params == NULL)
245     return(ERROR(ERRDOS,ERRnomem));
246
247   bzero(params,28);
248   SSVAL(params,0,fnum);
249   SSVAL(params,2,fmode);
250   put_dos_date2(params,4, mtime);
251   SIVAL(params,8, size);
252   SSVAL(params,12,rmode);
253
254   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
255     smb_action |= EXTENDED_OPLOCK_GRANTED;
256   }
257
258   SSVAL(params,18,smb_action);
259   SIVAL(params,20,inode);
260  
261   /* Send the required number of replies */
262   send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0);
263
264   return -1;
265 }
266
267 /****************************************************************************
268   get a level dependent lanman2 dir entry.
269 ****************************************************************************/
270 static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_level,
271                                  int requires_resume_key,
272                                  BOOL dont_descend,char **ppdata, 
273                                  char *base_data, int space_remaining, 
274                                  BOOL *out_of_space,
275                                  int *last_name_off)
276 {
277   char *dname;
278   BOOL found = False;
279   struct stat sbuf;
280   pstring mask;
281   pstring pathreal;
282   pstring fname;
283   BOOL matched;
284   char *p, *pdata = *ppdata;
285   int reskey=0, prev_dirpos=0;
286   int mode=0;
287   uint32 size=0,len;
288   uint32 mdate=0, adate=0, cdate=0;
289   char *nameptr;
290   BOOL isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
291                     strequal(Connections[cnum].dirpath,".") ||
292                     strequal(Connections[cnum].dirpath,"/"));
293   BOOL was_8_3;
294   int nt_extmode; /* Used for NT connections instead of mode */
295   BOOL needslash = ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
296
297   *fname = 0;
298   *out_of_space = False;
299
300   if (!Connections[cnum].dirptr)
301     return(False);
302
303   p = strrchr(path_mask,'/');
304   if(p != NULL)
305     {
306       if(p[1] == '\0')
307         strcpy(mask,"*.*");
308       else
309         pstrcpy(mask, p+1);
310     }
311   else
312     pstrcpy(mask, path_mask);
313
314   while (!found)
315     {
316       /* Needed if we run out of space */
317       prev_dirpos = TellDir(Connections[cnum].dirptr);
318       dname = ReadDirName(Connections[cnum].dirptr);
319
320       reskey = TellDir(Connections[cnum].dirptr);
321
322       DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
323                Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
324       
325       if (!dname) 
326         return(False);
327
328       matched = False;
329
330       pstrcpy(fname,dname);      
331
332       if(mask_match(fname, mask, case_sensitive, True))
333         {
334           BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
335           if (dont_descend && !isdots)
336             continue;
337           
338           if (isrootdir && isdots)
339             continue;
340
341           pstrcpy(pathreal,Connections[cnum].dirpath);
342           if(needslash)
343             strcat(pathreal,"/");
344           strcat(pathreal,dname);
345           if (sys_stat(pathreal,&sbuf) != 0) 
346             {
347               DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno)));
348               continue;
349             }
350
351           mode = dos_mode(cnum,pathreal,&sbuf);
352
353           if (!dir_check_ftype(cnum,mode,&sbuf,dirtype)) {
354             DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
355             continue;
356           }
357
358           size = sbuf.st_size;
359           mdate = sbuf.st_mtime;
360           adate = sbuf.st_atime;
361           cdate = sbuf.st_ctime;
362           if(mode & aDIR)
363             size = 0;
364
365           DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
366           
367           found = True;
368         }
369     }
370
371   name_map_mangle(fname,False,SNUM(cnum));
372
373   p = pdata;
374   nameptr = p;
375
376   nt_extmode = mode ? mode : NT_FILE_ATTRIBUTE_NORMAL;
377
378   switch (info_level)
379     {
380     case 1:
381       if(requires_resume_key) {
382         SIVAL(p,0,reskey);
383         p += 4;
384       }
385       put_dos_date2(p,l1_fdateCreation,cdate);
386       put_dos_date2(p,l1_fdateLastAccess,adate);
387       put_dos_date2(p,l1_fdateLastWrite,mdate);
388       SIVAL(p,l1_cbFile,size);
389       SIVAL(p,l1_cbFileAlloc,ROUNDUP(size,1024));
390       SSVAL(p,l1_attrFile,mode);
391       SCVAL(p,l1_cchName,strlen(fname));
392       strcpy(p + l1_achName, fname);
393       nameptr = p + l1_achName;
394       p += l1_achName + strlen(fname) + 1;
395       break;
396
397     case 2:
398       /* info_level 2 */
399       if(requires_resume_key) {
400         SIVAL(p,0,reskey);
401         p += 4;
402       }
403       put_dos_date2(p,l2_fdateCreation,cdate);
404       put_dos_date2(p,l2_fdateLastAccess,adate);
405       put_dos_date2(p,l2_fdateLastWrite,mdate);
406       SIVAL(p,l2_cbFile,size);
407       SIVAL(p,l2_cbFileAlloc,ROUNDUP(size,1024));
408       SSVAL(p,l2_attrFile,mode);
409       SIVAL(p,l2_cbList,0); /* No extended attributes */
410       SCVAL(p,l2_cchName,strlen(fname));
411       strcpy(p + l2_achName, fname);
412       nameptr = p + l2_achName;
413       p += l2_achName + strlen(fname) + 1;
414       break;
415
416     case 3:
417       SIVAL(p,0,reskey);
418       put_dos_date2(p,4,cdate);
419       put_dos_date2(p,8,adate);
420       put_dos_date2(p,12,mdate);
421       SIVAL(p,16,size);
422       SIVAL(p,20,ROUNDUP(size,1024));
423       SSVAL(p,24,mode);
424       SIVAL(p,26,4);
425       CVAL(p,30) = strlen(fname);
426       strcpy(p+31, fname);
427       nameptr = p+31;
428       p += 31 + strlen(fname) + 1;
429       break;
430
431     case 4:
432       if(requires_resume_key) {
433         SIVAL(p,0,reskey);
434         p += 4;
435       }
436       SIVAL(p,0,33+strlen(fname)+1);
437       put_dos_date2(p,4,cdate);
438       put_dos_date2(p,8,adate);
439       put_dos_date2(p,12,mdate);
440       SIVAL(p,16,size);
441       SIVAL(p,20,ROUNDUP(size,1024));
442       SSVAL(p,24,mode);
443       CVAL(p,32) = strlen(fname);
444       strcpy(p + 33, fname);
445       nameptr = p+33;
446       p += 33 + strlen(fname) + 1;
447       break;
448
449     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
450       was_8_3 = is_8_3(fname, True);
451       len = 94+strlen(fname);
452       len = (len + 3) & ~3;
453       SIVAL(p,0,len); p += 4;
454       SIVAL(p,0,reskey); p += 4;
455       put_long_date(p,cdate); p += 8;
456       put_long_date(p,adate); p += 8;
457       put_long_date(p,mdate); p += 8;
458       put_long_date(p,mdate); p += 8;
459       SIVAL(p,0,size); p += 8;
460       SIVAL(p,0,size); p += 8;
461       SIVAL(p,0,nt_extmode); p += 4;
462       SIVAL(p,0,strlen(fname)); p += 4;
463       SIVAL(p,0,0); p += 4;
464       if (!was_8_3) {
465         strcpy(p+2,fname);
466         if (!name_map_mangle(p+2,True,SNUM(cnum)))
467           (p+2)[12] = 0;
468       } else
469         *(p+2) = 0;
470       strupper(p+2);
471       SSVAL(p,0,strlen(p+2));
472       p += 2 + 24;
473       /* nameptr = p;  */
474       strcpy(p,fname); p += strlen(p);
475       p = pdata + len;
476       break;
477
478     case SMB_FIND_FILE_DIRECTORY_INFO:
479       len = 64+strlen(fname);
480       len = (len + 3) & ~3;
481       SIVAL(p,0,len); p += 4;
482       SIVAL(p,0,reskey); p += 4;
483       put_long_date(p,cdate); p += 8;
484       put_long_date(p,adate); p += 8;
485       put_long_date(p,mdate); p += 8;
486       put_long_date(p,mdate); p += 8;
487       SIVAL(p,0,size); p += 8;
488       SIVAL(p,0,size); p += 8;
489       SIVAL(p,0,nt_extmode); p += 4;
490       SIVAL(p,0,strlen(fname)); p += 4;
491       strcpy(p,fname);
492       p = pdata + len;
493       break;
494       
495       
496     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
497       len = 68+strlen(fname);
498       len = (len + 3) & ~3;
499       SIVAL(p,0,len); p += 4;
500       SIVAL(p,0,reskey); p += 4;
501       put_long_date(p,cdate); p += 8;
502       put_long_date(p,adate); p += 8;
503       put_long_date(p,mdate); p += 8;
504       put_long_date(p,mdate); p += 8;
505       SIVAL(p,0,size); p += 8;
506       SIVAL(p,0,size); p += 8;
507       SIVAL(p,0,nt_extmode); p += 4;
508       SIVAL(p,0,strlen(fname)); p += 4;
509       SIVAL(p,0,0); p += 4;
510       strcpy(p,fname);
511       p = pdata + len;
512       break;
513
514     case SMB_FIND_FILE_NAMES_INFO:
515       len = 12+strlen(fname);
516       len = (len + 3) & ~3;
517       SIVAL(p,0,len); p += 4;
518       SIVAL(p,0,reskey); p += 4;
519       SIVAL(p,0,strlen(fname)); p += 4;
520       strcpy(p,fname);
521       p = pdata + len;
522       break;
523
524     default:      
525       return(False);
526     }
527
528
529   if (PTR_DIFF(p,pdata) > space_remaining) {
530     /* Move the dirptr back to prev_dirpos */
531     SeekDir(Connections[cnum].dirptr, prev_dirpos);
532     *out_of_space = True;
533     DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
534     return False; /* Not finished - just out of space */
535   }
536
537   /* Setup the last_filename pointer, as an offset from base_data */
538   *last_name_off = PTR_DIFF(nameptr,base_data);
539   /* Advance the data pointer to the next slot */
540   *ppdata = p;
541   return(found);
542 }
543   
544 /****************************************************************************
545   reply to a TRANS2_FINDFIRST
546 ****************************************************************************/
547 static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum, 
548                          char **pparams, char **ppdata)
549 {
550   /* We must be careful here that we don't return more than the
551      allowed number of data bytes. If this means returning fewer than
552      maxentries then so be it. We assume that the redirector has
553      enough room for the fixed number of parameter bytes it has
554      requested. */
555   uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt);
556   char *params = *pparams;
557   char *pdata = *ppdata;
558   int dirtype = SVAL(params,0);
559   int maxentries = SVAL(params,2);
560   BOOL close_after_first = BITSETW(params+4,0);
561   BOOL close_if_end = BITSETW(params+4,1);
562   BOOL requires_resume_key = BITSETW(params+4,2);
563   int info_level = SVAL(params,6);
564   pstring directory;
565   pstring mask;
566   char *p, *wcard;
567   int last_name_off=0;
568   int dptr_num = -1;
569   int numentries = 0;
570   int i;
571   BOOL finished = False;
572   BOOL dont_descend = False;
573   BOOL out_of_space = False;
574   int space_remaining;
575   BOOL bad_path = False;
576
577   *directory = *mask = 0;
578
579   DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
580            dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
581            info_level, max_data_bytes));
582   
583   switch (info_level) 
584     {
585     case 1:
586     case 2:
587     case 3:
588     case 4:
589     case SMB_FIND_FILE_DIRECTORY_INFO:
590     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
591     case SMB_FIND_FILE_NAMES_INFO:
592     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
593       break;
594     default:
595       return(ERROR(ERRDOS,ERRunknownlevel));
596     }
597
598   pstrcpy(directory, params + 12); /* Complete directory path with 
599                                      wildcard mask appended */
600
601   DEBUG(5,("path=%s\n",directory));
602
603   unix_convert(directory,cnum,0,&bad_path);
604   if(!check_name(directory,cnum)) {
605     if((errno == ENOENT) && bad_path)
606     {
607       unix_ERR_class = ERRDOS;
608       unix_ERR_code = ERRbadpath;
609     }
610
611 #if 0
612     /* Ugly - NT specific hack - maybe not needed ? (JRA) */
613     if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && 
614        (get_remote_arch() == RA_WINNT))
615     {
616       unix_ERR_class = ERRDOS;
617       unix_ERR_code = ERRbaddirectory;
618     }
619 #endif 
620
621     return(ERROR(ERRDOS,ERRbadpath));
622   }
623
624   p = strrchr(directory,'/');
625   if(p == NULL) {
626     strcpy(mask,directory);
627     strcpy(directory,"./");
628   } else {
629     strcpy(mask,p+1);
630     *p = 0;
631   }
632
633   DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
634
635   pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
636   if(!*ppdata)
637     return(ERROR(ERRDOS,ERRnomem));
638   bzero(pdata,max_data_bytes);
639
640   /* Realloc the params space */
641   params = *pparams = Realloc(*pparams, 10);
642   if(params == NULL)
643     return(ERROR(ERRDOS,ERRnomem));
644
645   dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid));
646   if (dptr_num < 0)
647     {
648       if(dptr_num == -2)
649       {
650         if((errno == ENOENT) && bad_path)
651         {
652           unix_ERR_class = ERRDOS;
653           unix_ERR_code = ERRbadpath;
654         }
655
656 #if 0
657         /* Ugly - NT specific hack - maybe not needed ? (JRA) */
658         if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && 
659            (get_remote_arch() == RA_WINNT))
660         {
661           unix_ERR_class = ERRDOS;
662           unix_ERR_code = ERRbaddirectory;
663         }
664 #endif
665
666         return (UNIXERROR(ERRDOS,ERRbadpath));
667       }
668       return(ERROR(ERRDOS,ERRbadpath));
669     }
670
671   /* convert the formatted masks */
672   {
673     p = mask;
674     while (*p) {
675       if (*p == '<') *p = '*';
676       if (*p == '>') *p = '?';
677       if (*p == '"') *p = '.';
678       p++;
679     }
680   }
681   
682   /* a special case for 16 bit apps */
683   if (strequal(mask,"????????.???")) strcpy(mask,"*");
684
685   /* handle broken clients that send us old 8.3 format */
686   string_sub(mask,"????????","*");
687   string_sub(mask,".???",".*");
688
689   /* Save the wildcard match and attribs we are using on this directory - 
690      needed as lanman2 assumes these are being saved between calls */
691
692   if(!(wcard = strdup(mask))) {
693     dptr_close(dptr_num);
694     return(ERROR(ERRDOS,ERRnomem));
695   }
696
697   dptr_set_wcard(dptr_num, wcard);
698   dptr_set_attr(dptr_num, dirtype);
699
700   DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
701
702   /* We don't need to check for VOL here as this is returned by 
703      a different TRANS2 call. */
704   
705   DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
706            Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
707   if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
708     dont_descend = True;
709     
710   p = pdata;
711   space_remaining = max_data_bytes;
712   out_of_space = False;
713
714   for (i=0;(i<maxentries) && !finished && !out_of_space;i++)
715     {
716
717       /* this is a heuristic to avoid seeking the dirptr except when 
718          absolutely necessary. It allows for a filename of about 40 chars */
719       if (space_remaining < DIRLEN_GUESS && numentries > 0)
720         {
721           out_of_space = True;
722           finished = False;
723         }
724       else
725         {
726           finished = 
727             !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
728                                    requires_resume_key,dont_descend,
729                                    &p,pdata,space_remaining, &out_of_space,
730                                    &last_name_off);
731         }
732
733       if (finished && out_of_space)
734         finished = False;
735
736       if (!finished && !out_of_space)
737         numentries++;
738       space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
739     }
740   
741   /* Check if we can close the dirptr */
742   if(close_after_first || (finished && close_if_end))
743     {
744       dptr_close(dptr_num);
745       DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
746       dptr_num = -1;
747     }
748
749   /* At this point pdata points to numentries directory entries. */
750
751   /* Set up the return parameter block */
752   SSVAL(params,0,dptr_num);
753   SSVAL(params,2,numentries);
754   SSVAL(params,4,finished);
755   SSVAL(params,6,0); /* Never an EA error */
756   SSVAL(params,8,last_name_off);
757
758   send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
759
760   if ((! *directory) && dptr_path(dptr_num))
761     sprintf(directory,"(%s)",dptr_path(dptr_num));
762
763   DEBUG(4,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
764         timestring(),
765         smb_fn_name(CVAL(inbuf,smb_com)), 
766         mask,directory,cnum,dirtype,numentries));
767
768   return(-1);
769 }
770
771
772 /****************************************************************************
773   reply to a TRANS2_FINDNEXT
774 ****************************************************************************/
775 static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsize,
776                         int cnum, char **pparams, char **ppdata)
777 {
778   /* We must be careful here that we don't return more than the
779      allowed number of data bytes. If this means returning fewer than
780      maxentries then so be it. We assume that the redirector has
781      enough room for the fixed number of parameter bytes it has
782      requested. */
783   int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
784   char *params = *pparams;
785   char *pdata = *ppdata;
786   int16 dptr_num = SVAL(params,0);
787   int maxentries = SVAL(params,2);
788   uint16 info_level = SVAL(params,4);
789   uint32 resume_key = IVAL(params,6);
790   BOOL close_after_request = BITSETW(params+10,0);
791   BOOL close_if_end = BITSETW(params+10,1);
792   BOOL requires_resume_key = BITSETW(params+10,2);
793   BOOL continue_bit = BITSETW(params+10,3);
794   pstring mask;
795   pstring directory;
796   char *p;
797   uint16 dirtype;
798   int numentries = 0;
799   int i, last_name_off=0;
800   BOOL finished = False;
801   BOOL dont_descend = False;
802   BOOL out_of_space = False;
803   int space_remaining;
804
805   *mask = *directory = 0;
806
807   DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, close_after_request=%d, close_if_end = %d requires_resume_key = %d resume_key = %d continue=%d level = %d\n",
808            dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, 
809            requires_resume_key, resume_key, continue_bit, info_level));
810
811   switch (info_level) 
812     {
813     case 1:
814     case 2:
815     case 3:
816     case 4:
817     case SMB_FIND_FILE_DIRECTORY_INFO:
818     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
819     case SMB_FIND_FILE_NAMES_INFO:
820     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
821       break;
822     default:
823       return(ERROR(ERRDOS,ERRunknownlevel));
824     }
825
826   pdata = *ppdata = Realloc( *ppdata, max_data_bytes + 1024);
827   if(!*ppdata)
828     return(ERROR(ERRDOS,ERRnomem));
829   bzero(pdata,max_data_bytes);
830
831   /* Realloc the params space */
832   params = *pparams = Realloc(*pparams, 6*SIZEOFWORD);
833   if(!params)
834     return(ERROR(ERRDOS,ERRnomem));
835
836   /* Check that the dptr is valid */
837   if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num)))
838     return(ERROR(ERRDOS,ERRnofiles));
839
840   string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
841
842   /* Get the wildcard mask from the dptr */
843   if((p = dptr_wcard(dptr_num))== NULL) {
844     DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
845     return (ERROR(ERRDOS,ERRnofiles));
846   }
847   strcpy(mask, p);
848   strcpy(directory,Connections[cnum].dirpath);
849
850   /* Get the attr mask from the dptr */
851   dirtype = dptr_attr(dptr_num);
852
853   DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%X,%d)\n",
854            dptr_num, mask, dirtype, 
855            Connections[cnum].dirptr,
856            TellDir(Connections[cnum].dirptr)));
857
858   /* We don't need to check for VOL here as this is returned by 
859      a different TRANS2 call. */
860
861   DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
862   if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
863     dont_descend = True;
864     
865   p = pdata;
866   space_remaining = max_data_bytes;
867   out_of_space = False;
868
869   /* If we have a resume key - seek to the correct position. */
870   if(requires_resume_key && !continue_bit)
871     SeekDir(Connections[cnum].dirptr, resume_key);
872
873   for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
874     {
875       /* this is a heuristic to avoid seeking the dirptr except when 
876          absolutely necessary. It allows for a filename of about 40 chars */
877       if (space_remaining < DIRLEN_GUESS && numentries > 0)
878         {
879           out_of_space = True;
880           finished = False;
881         }
882       else
883         {
884           finished = 
885             !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
886                                    requires_resume_key,dont_descend,
887                                    &p,pdata,space_remaining, &out_of_space,
888                                    &last_name_off);
889         }
890
891       if (finished && out_of_space)
892         finished = False;
893
894       if (!finished && !out_of_space)
895         numentries++;
896       space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
897     }
898   
899   /* Check if we can close the dirptr */
900   if(close_after_request || (finished && close_if_end))
901     {
902       dptr_close(dptr_num); /* This frees up the saved mask */
903       DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
904       dptr_num = -1;
905     }
906
907
908   /* Set up the return parameter block */
909   SSVAL(params,0,numentries);
910   SSVAL(params,2,finished);
911   SSVAL(params,4,0); /* Never an EA error */
912   SSVAL(params,6,last_name_off);
913
914   send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
915
916   if ((! *directory) && dptr_path(dptr_num))
917     sprintf(directory,"(%s)",dptr_path(dptr_num));
918
919   DEBUG(3,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
920            timestring(),
921            smb_fn_name(CVAL(inbuf,smb_com)), 
922            mask,directory,cnum,dirtype,numentries));
923
924   return(-1);
925 }
926
927 /****************************************************************************
928   reply to a TRANS2_QFSINFO (query filesystem info)
929 ****************************************************************************/
930 static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
931                         int cnum, char **pparams, char **ppdata)
932 {
933   char *pdata = *ppdata;
934   char *params = *pparams;
935   uint16 info_level = SVAL(params,0);
936   int data_len;
937   struct stat st;
938   char *vname = volume_label(SNUM(cnum));
939   
940   DEBUG(3,("call_trans2qfsinfo: cnum = %d, level = %d\n", cnum, info_level));
941
942   if(sys_stat(".",&st)!=0) {
943     DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
944     return (ERROR(ERRSRV,ERRinvdevice));
945   }
946
947   pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,1024);
948
949   switch (info_level) 
950     {
951     case 1:
952       {
953         int dfree,dsize,bsize;
954         data_len = 18;
955         sys_disk_free(".",&bsize,&dfree,&dsize);        
956         SIVAL(pdata,l1_idFileSystem,st.st_dev);
957         SIVAL(pdata,l1_cSectorUnit,bsize/512);
958         SIVAL(pdata,l1_cUnit,dsize);
959         SIVAL(pdata,l1_cUnitAvail,dfree);
960         SSVAL(pdata,l1_cbSector,512);
961         DEBUG(5,("call_trans2qfsinfo : bsize=%d, id=%x, cSectorUnit=%d, cUnit=%d, cUnitAvail=%d, cbSector=%d\n",
962                  bsize, st.st_dev, bsize/512, dsize, dfree, 512));
963         break;
964     }
965     case 2:
966     { 
967       /* Return volume name */
968       int volname_len = MIN(strlen(vname),11);
969       data_len = l2_vol_szVolLabel + volname_len + 1;
970       put_dos_date2(pdata,l2_vol_fdateCreation,st.st_ctime);
971       SCVAL(pdata,l2_vol_cch,volname_len);
972       StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
973       DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime, volname_len,
974                pdata+l2_vol_szVolLabel));
975       break;
976     }
977     case SMB_QUERY_FS_ATTRIBUTE_INFO:
978       data_len = 12 + 2*strlen(FSTYPE_STRING);
979       SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
980       SIVAL(pdata,4,128); /* Max filename component length */
981       SIVAL(pdata,8,2*strlen(FSTYPE_STRING));
982       PutUniCode(pdata+12,FSTYPE_STRING);
983       break;
984     case SMB_QUERY_FS_LABEL_INFO:
985       data_len = 4 + strlen(vname);
986       SIVAL(pdata,0,strlen(vname));
987       strcpy(pdata+4,vname);      
988       break;
989     case SMB_QUERY_FS_VOLUME_INFO:      
990       data_len = 18 + 2*strlen(vname);
991       SIVAL(pdata,12,2*strlen(vname));
992       PutUniCode(pdata+18,vname);      
993       DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", strlen(vname),
994                vname));
995       break;
996     case SMB_QUERY_FS_SIZE_INFO:
997       {
998         int dfree,dsize,bsize;
999         data_len = 24;
1000         sys_disk_free(".",&bsize,&dfree,&dsize);        
1001         SIVAL(pdata,0,dsize);
1002         SIVAL(pdata,8,dfree);
1003         SIVAL(pdata,16,bsize/512);
1004         SIVAL(pdata,20,512);
1005       }
1006       break;
1007     case SMB_QUERY_FS_DEVICE_INFO:
1008       data_len = 8;
1009       SIVAL(pdata,0,0); /* dev type */
1010       SIVAL(pdata,4,0); /* characteristics */
1011       break;
1012     default:
1013       return(ERROR(ERRDOS,ERRunknownlevel));
1014     }
1015
1016
1017   send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len);
1018
1019   DEBUG(4,("%s %s info_level =%d\n",timestring(),smb_fn_name(CVAL(inbuf,smb_com)), info_level));
1020
1021   return -1;
1022 }
1023
1024 /****************************************************************************
1025   reply to a TRANS2_SETFSINFO (set filesystem info)
1026 ****************************************************************************/
1027 static int call_trans2setfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
1028                         int cnum, char **pparams, char **ppdata)
1029 {
1030   /* Just say yes we did it - there is nothing that
1031      can be set here so it doesn't matter. */
1032   int outsize;
1033   DEBUG(3,("call_trans2setfsinfo\n"));
1034
1035   if (!CAN_WRITE(cnum))
1036     return(ERROR(ERRSRV,ERRaccess));
1037
1038   outsize = set_message(outbuf,10,0,True);
1039
1040   return outsize;
1041 }
1042
1043 /****************************************************************************
1044   reply to a TRANS2_QFILEINFO (query file info by fileid)
1045 ****************************************************************************/
1046 static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length, 
1047                                     int bufsize,int cnum,
1048                                     char **pparams,char **ppdata,
1049                                     int total_data)
1050 {
1051   char *params = *pparams;
1052   char *pdata = *ppdata;
1053   uint16 tran_call = SVAL(inbuf, smb_setup0);
1054   uint16 info_level;
1055   int mode=0;
1056   int size=0;
1057   unsigned int data_size;
1058   struct stat sbuf;
1059   pstring fname1;
1060   char *fname;
1061   char *p;
1062   int l,pos;
1063   BOOL bad_path = False;
1064
1065   if (tran_call == TRANSACT2_QFILEINFO) {
1066     int16 fnum = SVALS(params,0);
1067     info_level = SVAL(params,2);
1068
1069     CHECK_FNUM(fnum,cnum);
1070     CHECK_ERROR(fnum);
1071
1072     fname = Files[fnum].name;
1073     if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
1074       DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno)));
1075       return(UNIXERROR(ERRDOS,ERRbadfid));
1076     }
1077     pos = lseek(Files[fnum].fd_ptr->fd,0,SEEK_CUR);
1078   } else {
1079     /* qpathinfo */
1080     info_level = SVAL(params,0);
1081     fname = &fname1[0];
1082     pstrcpy(fname,&params[6]);
1083     unix_convert(fname,cnum,0,&bad_path);
1084     if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
1085       DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
1086       if((errno == ENOENT) && bad_path)
1087       {
1088         unix_ERR_class = ERRDOS;
1089         unix_ERR_code = ERRbadpath;
1090       }
1091       return(UNIXERROR(ERRDOS,ERRbadpath));
1092     }
1093     pos = 0;
1094   }
1095
1096
1097   DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
1098            fname,info_level,tran_call,total_data));
1099
1100   p = strrchr(fname,'/'); 
1101   if (!p) 
1102     p = fname;
1103   else
1104     p++;
1105   l = strlen(p);  
1106   mode = dos_mode(cnum,fname,&sbuf);
1107   size = sbuf.st_size;
1108   if (mode & aDIR) size = 0;
1109   
1110   params = *pparams = Realloc(*pparams,2); bzero(params,2);
1111   data_size = 1024;
1112   pdata = *ppdata = Realloc(*ppdata, data_size); 
1113
1114   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1115     /* uggh, EAs for OS2 */
1116     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1117     return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
1118   }
1119
1120   bzero(pdata,data_size);
1121
1122   switch (info_level) 
1123     {
1124     case SMB_INFO_STANDARD:
1125     case SMB_INFO_QUERY_EA_SIZE:
1126       data_size = (info_level==1?22:26);
1127       put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime); /* create = inode mod */
1128       put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); /* access time */
1129       put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
1130       SIVAL(pdata,l1_cbFile,size);
1131       SIVAL(pdata,l1_cbFileAlloc,ROUNDUP(size,1024));
1132       SSVAL(pdata,l1_attrFile,mode);
1133       SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
1134       break;
1135
1136     case SMB_INFO_QUERY_EAS_FROM_LIST:
1137       data_size = 24;
1138       put_dos_date2(pdata,0,sbuf.st_ctime); /* create time = inode mod time */
1139       put_dos_date2(pdata,4,sbuf.st_atime);
1140       put_dos_date2(pdata,8,sbuf.st_mtime);
1141       SIVAL(pdata,12,size);
1142       SIVAL(pdata,16,ROUNDUP(size,1024));
1143       SIVAL(pdata,20,mode);
1144       break;
1145
1146     case SMB_INFO_QUERY_ALL_EAS:
1147       data_size = 4;
1148       SIVAL(pdata,0,data_size);
1149       break;
1150
1151     case 6:
1152       return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */      
1153
1154     case SMB_QUERY_FILE_BASIC_INFO:
1155       data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
1156       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1157       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1158       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1159       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1160       SIVAL(pdata,32,mode);
1161
1162       DEBUG(5,("SMB_QFBI - "));
1163       DEBUG(5,("create: %s ", ctime(&sbuf.st_ctime)));
1164       DEBUG(5,("access: %s ", ctime(&sbuf.st_atime)));
1165       DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
1166       DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
1167       DEBUG(5,("mode: %x\n", mode));
1168
1169       break;
1170
1171     case SMB_QUERY_FILE_STANDARD_INFO:
1172       data_size = 22;
1173       SIVAL(pdata,0,size);
1174       SIVAL(pdata,8,size);
1175       SIVAL(pdata,16,sbuf.st_nlink);
1176       CVAL(pdata,20) = 0;
1177       CVAL(pdata,21) = (mode&aDIR)?1:0;
1178       break;
1179
1180     case SMB_QUERY_FILE_EA_INFO:
1181       data_size = 4;
1182       break;
1183
1184     case SMB_QUERY_FILE_NAME_INFO:
1185     case SMB_QUERY_FILE_ALT_NAME_INFO:
1186       data_size = 4 + l;
1187       SIVAL(pdata,0,l);
1188       pstrcpy(pdata+4,fname);
1189       break;
1190     case SMB_QUERY_FILE_ALLOCATION_INFO:
1191     case SMB_QUERY_FILE_END_OF_FILEINFO:
1192       data_size = 8;
1193       SIVAL(pdata,0,size);
1194       break;
1195
1196     case SMB_QUERY_FILE_ALL_INFO:
1197       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1198       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1199       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1200       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1201       SIVAL(pdata,32,mode);
1202       pdata += 40;
1203       SIVAL(pdata,0,size);
1204       SIVAL(pdata,8,size);
1205       SIVAL(pdata,16,sbuf.st_nlink);
1206       CVAL(pdata,20) = 0;
1207       CVAL(pdata,21) = (mode&aDIR)?1:0;
1208       pdata += 24;
1209       pdata += 8; /* index number */
1210       pdata += 4; /* EA info */
1211       if (mode & aRONLY)
1212         SIVAL(pdata,0,0xA9);
1213       else
1214         SIVAL(pdata,0,0xd01BF);
1215       pdata += 4;
1216       SIVAL(pdata,0,pos); /* current offset */
1217       pdata += 8;
1218       SIVAL(pdata,0,mode); /* is this the right sort of mode info? */
1219       pdata += 4;
1220       pdata += 4; /* alignment */
1221       SIVAL(pdata,0,l);
1222       pstrcpy(pdata+4,fname);
1223       pdata += 4 + l;
1224       data_size = PTR_DIFF(pdata,(*ppdata));
1225       break;
1226
1227     case SMB_QUERY_FILE_STREAM_INFO:
1228       data_size = 24 + l;
1229       SIVAL(pdata,0,pos);
1230       SIVAL(pdata,4,size);
1231       SIVAL(pdata,12,size);
1232       SIVAL(pdata,20,l);        
1233       pstrcpy(pdata+24,fname);
1234       break;
1235     default:
1236       return(ERROR(ERRDOS,ERRunknownlevel));
1237     }
1238
1239   send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size);
1240
1241   return(-1);
1242 }
1243
1244 /****************************************************************************
1245   reply to a TRANS2_SETFILEINFO (set file info by fileid)
1246 ****************************************************************************/
1247 static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length, 
1248                                       int bufsize, int cnum, char **pparams, 
1249                                       char **ppdata, int total_data)
1250 {
1251   char *params = *pparams;
1252   char *pdata = *ppdata;
1253   uint16 tran_call = SVAL(inbuf, smb_setup0);
1254   uint16 info_level;
1255   int mode=0;
1256   int size=0;
1257   struct utimbuf tvs;
1258   struct stat st;
1259   pstring fname1;
1260   char *fname;
1261   int fd = -1;
1262   BOOL bad_path = False;
1263
1264   if (!CAN_WRITE(cnum))
1265     return(ERROR(ERRSRV,ERRaccess));
1266
1267   if (tran_call == TRANSACT2_SETFILEINFO) {
1268     int16 fnum = SVALS(params,0);
1269     info_level = SVAL(params,2);    
1270
1271     CHECK_FNUM(fnum,cnum);
1272     CHECK_ERROR(fnum);
1273
1274     fname = Files[fnum].name;
1275     fd = Files[fnum].fd_ptr->fd;
1276
1277     if(fstat(fd,&st)!=0) {
1278       DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
1279       return(ERROR(ERRDOS,ERRbadpath));
1280     }
1281   } else {
1282     /* set path info */
1283     info_level = SVAL(params,0);    
1284     fname = fname1;
1285     pstrcpy(fname,&params[6]);
1286     unix_convert(fname,cnum,0,&bad_path);
1287     if(!check_name(fname, cnum))
1288     {
1289       if((errno == ENOENT) && bad_path)
1290       {
1291         unix_ERR_class = ERRDOS;
1292         unix_ERR_code = ERRbadpath;
1293       }
1294       return(UNIXERROR(ERRDOS,ERRbadpath));
1295     }
1296  
1297     if(sys_stat(fname,&st)!=0) {
1298       DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
1299       if((errno == ENOENT) && bad_path)
1300       {
1301         unix_ERR_class = ERRDOS;
1302         unix_ERR_code = ERRbadpath;
1303       }
1304       return(UNIXERROR(ERRDOS,ERRbadpath));
1305     }    
1306   }
1307
1308   DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
1309            tran_call,fname,info_level,total_data));
1310
1311   /* Realloc the parameter and data sizes */
1312   params = *pparams = Realloc(*pparams,2); SSVAL(params,0,0);
1313   if(params == NULL)
1314     return(ERROR(ERRDOS,ERRnomem));
1315
1316   size = st.st_size;
1317   tvs.modtime = st.st_mtime;
1318   tvs.actime = st.st_atime;
1319   mode = dos_mode(cnum,fname,&st);
1320
1321   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1322     /* uggh, EAs for OS2 */
1323     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1324     return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
1325   }
1326
1327   switch (info_level)
1328   {
1329     case SMB_INFO_STANDARD:
1330     case SMB_INFO_QUERY_EA_SIZE:
1331     {
1332       /* access time */
1333       tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
1334
1335       /* write time */
1336       tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
1337
1338       mode = SVAL(pdata,l1_attrFile);
1339       size = IVAL(pdata,l1_cbFile);
1340       break;
1341     }
1342
1343     /* XXXX um, i don't think this is right.
1344        it's also not in the cifs6.txt spec.
1345      */
1346     case SMB_INFO_QUERY_EAS_FROM_LIST:
1347       tvs.actime = make_unix_date2(pdata+8);
1348       tvs.modtime = make_unix_date2(pdata+12);
1349       size = IVAL(pdata,16);
1350       mode = IVAL(pdata,24);
1351       break;
1352
1353     /* XXXX nor this.  not in cifs6.txt, either. */
1354     case SMB_INFO_QUERY_ALL_EAS:
1355       tvs.actime = make_unix_date2(pdata+8);
1356       tvs.modtime = make_unix_date2(pdata+12);
1357       size = IVAL(pdata,16);
1358       mode = IVAL(pdata,24);
1359       break;
1360
1361     case SMB_SET_FILE_BASIC_INFO:
1362     {
1363       /* Ignore create time at offset pdata. */
1364
1365       /* access time */
1366       tvs.actime = interpret_long_date(pdata+8);
1367
1368       /* write time + changed time, combined. */
1369       tvs.modtime=MAX(interpret_long_date(pdata+16),
1370                       interpret_long_date(pdata+24));
1371
1372 #if 0 /* Needs more testing... */
1373       /* Test from Luke to prevent Win95 from
1374          setting incorrect values here.
1375        */
1376       if (tvs.actime < tvs.modtime)
1377         return(ERROR(ERRDOS,ERRnoaccess));
1378 #endif /* Needs more testing... */
1379
1380       /* attributes */
1381       mode = IVAL(pdata,32);
1382       break;
1383     }
1384
1385     case SMB_SET_FILE_END_OF_FILE_INFO:
1386     {
1387       if (IVAL(pdata,4) != 0)   /* more than 32 bits? */
1388          return(ERROR(ERRDOS,ERRunknownlevel));
1389       size = IVAL(pdata,0);
1390       break;
1391     }
1392
1393     case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
1394     case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
1395     default:
1396     {
1397       return(ERROR(ERRDOS,ERRunknownlevel));
1398     }
1399   }
1400
1401   DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
1402   DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
1403   DEBUG(6,("size: %x "   , size));
1404   DEBUG(6,("mode: %x\n"  , mode));
1405
1406   /* get some defaults (no modifications) if any info is zero. */
1407   if (!tvs.actime) tvs.actime = st.st_atime;
1408   if (!tvs.modtime) tvs.modtime = st.st_mtime;
1409   if (!size) size = st.st_size;
1410
1411   /* Try and set the times, size and mode of this file -
1412      if they are different from the current values
1413    */
1414   if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
1415   {
1416     if(sys_utime(fname, &tvs)!=0)
1417     {
1418       return(ERROR(ERRDOS,ERRnoaccess));
1419     }
1420   }
1421
1422   /* check the mode isn't different, before changing it */
1423   if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL))
1424   {
1425     DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
1426     return(ERROR(ERRDOS,ERRnoaccess));
1427   }
1428
1429   if(size != st.st_size)
1430   {
1431     if (fd == -1)
1432     {
1433       fd = sys_open(fname,O_RDWR,0);
1434       if (fd == -1)
1435       {
1436         return(ERROR(ERRDOS,ERRbadpath));
1437       }
1438       set_filelen(fd, size);
1439       close(fd);
1440     }
1441     else
1442     {
1443       set_filelen(fd, size);
1444     }
1445   }
1446
1447   SSVAL(params,0,0);
1448
1449   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1450   
1451   return(-1);
1452 }
1453
1454 /****************************************************************************
1455   reply to a TRANS2_MKDIR (make directory with extended attributes).
1456 ****************************************************************************/
1457 static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
1458                         int cnum, char **pparams, char **ppdata)
1459 {
1460   char *params = *pparams;
1461   pstring directory;
1462   int ret = -1;
1463   BOOL bad_path = False;
1464
1465   if (!CAN_WRITE(cnum))
1466     return(ERROR(ERRSRV,ERRaccess));
1467
1468   pstrcpy(directory, &params[4]);
1469
1470   DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
1471
1472   unix_convert(directory,cnum,0,&bad_path);
1473   if (check_name(directory,cnum))
1474     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
1475   
1476   if(ret < 0)
1477     {
1478       DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
1479       if((errno == ENOENT) && bad_path)
1480       {
1481         unix_ERR_class = ERRDOS;
1482         unix_ERR_code = ERRbadpath;
1483       }
1484       return(UNIXERROR(ERRDOS,ERRnoaccess));
1485     }
1486
1487   /* Realloc the parameter and data sizes */
1488   params = *pparams = Realloc(*pparams,2);
1489   if(params == NULL)
1490     return(ERROR(ERRDOS,ERRnomem));
1491
1492   SSVAL(params,0,0);
1493
1494   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1495   
1496   return(-1);
1497 }
1498
1499 /****************************************************************************
1500   reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes)
1501   We don't actually do this - we just send a null response.
1502 ****************************************************************************/
1503 static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int bufsize,
1504                         int cnum, char **pparams, char **ppdata)
1505 {
1506   static uint16 fnf_handle = 257;
1507   char *params = *pparams;
1508   uint16 info_level = SVAL(params,4);
1509
1510   DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
1511
1512   switch (info_level) 
1513     {
1514     case 1:
1515     case 2:
1516       break;
1517     default:
1518       return(ERROR(ERRDOS,ERRunknownlevel));
1519     }
1520
1521   /* Realloc the parameter and data sizes */
1522   params = *pparams = Realloc(*pparams,6);
1523   if(params == NULL)
1524     return(ERROR(ERRDOS,ERRnomem));
1525
1526   SSVAL(params,0,fnf_handle);
1527   SSVAL(params,2,0); /* No changes */
1528   SSVAL(params,4,0); /* No EA errors */
1529
1530   fnf_handle++;
1531
1532   if(fnf_handle == 0)
1533     fnf_handle = 257;
1534
1535   send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0);
1536   
1537   return(-1);
1538 }
1539
1540 /****************************************************************************
1541   reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for 
1542   changes). Currently this does nothing.
1543 ****************************************************************************/
1544 static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int bufsize,
1545                         int cnum, char **pparams, char **ppdata)
1546 {
1547   char *params = *pparams;
1548
1549   DEBUG(3,("call_trans2findnotifynext\n"));
1550
1551   /* Realloc the parameter and data sizes */
1552   params = *pparams = Realloc(*pparams,4);
1553   if(params == NULL)
1554     return(ERROR(ERRDOS,ERRnomem));
1555
1556   SSVAL(params,0,0); /* No changes */
1557   SSVAL(params,2,0); /* No EA errors */
1558
1559   send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
1560   
1561   return(-1);
1562 }
1563
1564 /****************************************************************************
1565   reply to a SMBfindclose (stop trans2 directory search)
1566 ****************************************************************************/
1567 int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
1568 {
1569   int cnum;
1570   int outsize = 0;
1571   int16 dptr_num=SVALS(inbuf,smb_vwv0);
1572
1573   cnum = SVAL(inbuf,smb_tid);
1574
1575   DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1576
1577   dptr_close(dptr_num);
1578
1579   outsize = set_message(outbuf,0,0,True);
1580
1581   DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1582
1583   return(outsize);
1584 }
1585
1586 /****************************************************************************
1587   reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search)
1588 ****************************************************************************/
1589 int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize)
1590 {
1591   int cnum;
1592   int outsize = 0;
1593   int dptr_num= -1;
1594
1595   cnum = SVAL(inbuf,smb_tid);
1596   dptr_num = SVAL(inbuf,smb_vwv0);
1597
1598   DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1599
1600   /* We never give out valid handles for a 
1601      findnotifyfirst - so any dptr_num is ok here. 
1602      Just ignore it. */
1603
1604   outsize = set_message(outbuf,0,0,True);
1605
1606   DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1607
1608   return(outsize);
1609 }
1610
1611
1612 /****************************************************************************
1613   reply to a SMBtranss2 - just ignore it!
1614 ****************************************************************************/
1615 int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize)
1616 {
1617   DEBUG(4,("Ignoring transs2 of length %d\n",length));
1618   return(-1);
1619 }
1620
1621 /****************************************************************************
1622   reply to a SMBtrans2
1623 ****************************************************************************/
1624 int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
1625 {
1626   int outsize = 0;
1627   int cnum = SVAL(inbuf,smb_tid);
1628   unsigned int total_params = SVAL(inbuf, smb_tpscnt);
1629   unsigned int total_data =SVAL(inbuf, smb_tdscnt);
1630 #if 0
1631   unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
1632   unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
1633   unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
1634   BOOL close_tid = BITSETW(inbuf+smb_flags,0);
1635   BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
1636   int32 timeout = IVALS(inbuf,smb_timeout);
1637 #endif
1638   unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
1639   unsigned int tran_call = SVAL(inbuf, smb_setup0);
1640   char *params = NULL, *data = NULL;
1641   int num_params, num_params_sofar, num_data, num_data_sofar;
1642
1643   outsize = set_message(outbuf,0,0,True);
1644
1645   /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
1646      is so as a sanity check */
1647   if(suwcnt != 1 )
1648     {
1649       DEBUG(2,("Invalid smb_sucnt in trans2 call\n"));
1650       return(ERROR(ERRSRV,ERRerror));
1651     }
1652     
1653   /* Allocate the space for the maximum needed parameters and data */
1654   if (total_params > 0)
1655     params = (char *)malloc(total_params);
1656   if (total_data > 0)
1657     data = (char *)malloc(total_data);
1658   
1659   if ((total_params && !params)  || (total_data && !data))
1660     {
1661       DEBUG(2,("Out of memory in reply_trans2\n"));
1662       return(ERROR(ERRDOS,ERRnomem));
1663     }
1664
1665   /* Copy the param and data bytes sent with this request into
1666      the params buffer */
1667   num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
1668   num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
1669
1670   if (num_params > total_params || num_data > total_data)
1671           exit_server("invalid params in reply_trans2");
1672
1673   memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
1674   memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
1675
1676   if(num_data_sofar < total_data || num_params_sofar < total_params)
1677     {
1678     /* We need to send an interim response then receive the rest
1679        of the parameter/data bytes */
1680       outsize = set_message(outbuf,0,0,True);
1681       send_smb(Client,outbuf);
1682
1683       while( num_data_sofar < total_data || num_params_sofar < total_params)
1684         {
1685           if(!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
1686              CVAL(inbuf, smb_com) != SMBtranss2)
1687             {
1688               outsize = set_message(outbuf,0,0,True);
1689               DEBUG(2,("Invalid secondary trans2 packet\n"));
1690               free(params);
1691               free(data);
1692               return(ERROR(ERRSRV,ERRerror));
1693             }
1694       
1695           /* Revise total_params and total_data in case they have changed downwards */
1696           total_params = SVAL(inbuf, smb_tpscnt);
1697           total_data = SVAL(inbuf, smb_tdscnt);
1698           num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
1699           num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
1700           if (num_params_sofar > total_params || num_data_sofar > total_data)
1701                   exit_server("data overflow in trans2");
1702
1703           memcpy( &params[ SVAL(inbuf, smb_spsdisp)], 
1704                  smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
1705           memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
1706                  smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
1707         }
1708     }
1709
1710   if (Protocol >= PROTOCOL_NT1) {
1711     uint16 flg2 = SVAL(outbuf,smb_flg2);
1712     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1713   }
1714
1715   /* Now we must call the relevant TRANS2 function */
1716   switch(tran_call) 
1717     {
1718     case TRANSACT2_OPEN:
1719       outsize = call_trans2open(inbuf, outbuf, bufsize, cnum, &params, &data);
1720       break;
1721     case TRANSACT2_FINDFIRST:
1722       outsize = call_trans2findfirst(inbuf, outbuf, bufsize, cnum, &params, &data);
1723       break;
1724     case TRANSACT2_FINDNEXT:
1725       outsize = call_trans2findnext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1726       break;
1727     case TRANSACT2_QFSINFO:
1728       outsize = call_trans2qfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1729       break;
1730     case TRANSACT2_SETFSINFO:
1731       outsize = call_trans2setfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1732       break;
1733     case TRANSACT2_QPATHINFO:
1734     case TRANSACT2_QFILEINFO:
1735       outsize = call_trans2qfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1736       break;
1737     case TRANSACT2_SETPATHINFO:
1738     case TRANSACT2_SETFILEINFO:
1739       outsize = call_trans2setfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1740       break;
1741     case TRANSACT2_FINDNOTIFYFIRST:
1742       outsize = call_trans2findnotifyfirst(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1743       break;
1744     case TRANSACT2_FINDNOTIFYNEXT:
1745       outsize = call_trans2findnotifynext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1746       break;
1747     case TRANSACT2_MKDIR:
1748       outsize = call_trans2mkdir(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1749       break;
1750     default:
1751       /* Error in request */
1752       DEBUG(2,("%s Unknown request %d in trans2 call\n",timestring(), tran_call));
1753       if(params)
1754         free(params);
1755       if(data)
1756         free(data);
1757       return (ERROR(ERRSRV,ERRerror));
1758     }
1759
1760   /* As we do not know how many data packets will need to be
1761      returned here the various call_trans2xxxx calls
1762      must send their own. Thus a call_trans2xxx routine only
1763      returns a value other than -1 when it wants to send
1764      an error packet. 
1765   */
1766
1767   if(params)
1768     free(params);
1769   if(data)
1770     free(data);
1771   return outsize; /* If a correct response was needed the call_trans2xxx 
1772                      calls have already sent it. If outsize != -1 then it is
1773                      returning an error packet. */
1774 }