7f46604cce9dcade4c038b0e0367a2d0425ba967
[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     /* Ugly - NT specific hack - but needed (JRA) */
612     if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && 
613        (get_remote_arch() == RA_WINNT))
614     {
615       unix_ERR_class = ERRDOS;
616       unix_ERR_code = ERRbaddirectory;
617     }
618
619     return(ERROR(ERRDOS,ERRbadpath));
620   }
621
622   p = strrchr(directory,'/');
623   if(p == NULL) {
624     strcpy(mask,directory);
625     strcpy(directory,"./");
626   } else {
627     strcpy(mask,p+1);
628     *p = 0;
629   }
630
631   DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
632
633   pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
634   if(!*ppdata)
635     return(ERROR(ERRDOS,ERRnomem));
636   bzero(pdata,max_data_bytes);
637
638   /* Realloc the params space */
639   params = *pparams = Realloc(*pparams, 10);
640   if(params == NULL)
641     return(ERROR(ERRDOS,ERRnomem));
642
643   dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid));
644   if (dptr_num < 0)
645     {
646       if(dptr_num == -2)
647       {
648         if((errno == ENOENT) && bad_path)
649         {
650           unix_ERR_class = ERRDOS;
651           unix_ERR_code = ERRbadpath;
652         }
653
654         /* Ugly - NT specific hack - but needed (JRA) */
655         if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && 
656            (get_remote_arch() == RA_WINNT))
657         {
658           unix_ERR_class = ERRDOS;
659           unix_ERR_code = ERRbaddirectory;
660         }
661         return (UNIXERROR(ERRDOS,ERRbadpath));
662       }
663       return(ERROR(ERRDOS,ERRbadpath));
664     }
665
666   /* convert the formatted masks */
667   {
668     p = mask;
669     while (*p) {
670       if (*p == '<') *p = '*';
671       if (*p == '>') *p = '?';
672       if (*p == '"') *p = '.';
673       p++;
674     }
675   }
676   
677   /* a special case for 16 bit apps */
678   if (strequal(mask,"????????.???")) strcpy(mask,"*");
679
680   /* handle broken clients that send us old 8.3 format */
681   string_sub(mask,"????????","*");
682   string_sub(mask,".???",".*");
683
684   /* Save the wildcard match and attribs we are using on this directory - 
685      needed as lanman2 assumes these are being saved between calls */
686
687   if(!(wcard = strdup(mask))) {
688     dptr_close(dptr_num);
689     return(ERROR(ERRDOS,ERRnomem));
690   }
691
692   dptr_set_wcard(dptr_num, wcard);
693   dptr_set_attr(dptr_num, dirtype);
694
695   DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
696
697   /* We don't need to check for VOL here as this is returned by 
698      a different TRANS2 call. */
699   
700   DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
701            Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
702   if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
703     dont_descend = True;
704     
705   p = pdata;
706   space_remaining = max_data_bytes;
707   out_of_space = False;
708
709   for (i=0;(i<maxentries) && !finished && !out_of_space;i++)
710     {
711
712       /* this is a heuristic to avoid seeking the dirptr except when 
713          absolutely necessary. It allows for a filename of about 40 chars */
714       if (space_remaining < DIRLEN_GUESS && numentries > 0)
715         {
716           out_of_space = True;
717           finished = False;
718         }
719       else
720         {
721           finished = 
722             !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
723                                    requires_resume_key,dont_descend,
724                                    &p,pdata,space_remaining, &out_of_space,
725                                    &last_name_off);
726         }
727
728       if (finished && out_of_space)
729         finished = False;
730
731       if (!finished && !out_of_space)
732         numentries++;
733       space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
734     }
735   
736   /* Check if we can close the dirptr */
737   if(close_after_first || (finished && close_if_end))
738     {
739       dptr_close(dptr_num);
740       DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
741       dptr_num = -1;
742     }
743
744   /* At this point pdata points to numentries directory entries. */
745
746   /* Set up the return parameter block */
747   SSVAL(params,0,dptr_num);
748   SSVAL(params,2,numentries);
749   SSVAL(params,4,finished);
750   SSVAL(params,6,0); /* Never an EA error */
751   SSVAL(params,8,last_name_off);
752
753   send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
754
755   if ((! *directory) && dptr_path(dptr_num))
756     sprintf(directory,"(%s)",dptr_path(dptr_num));
757
758   DEBUG(4,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
759         timestring(),
760         smb_fn_name(CVAL(inbuf,smb_com)), 
761         mask,directory,cnum,dirtype,numentries));
762
763   return(-1);
764 }
765
766
767 /****************************************************************************
768   reply to a TRANS2_FINDNEXT
769 ****************************************************************************/
770 static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsize,
771                         int cnum, char **pparams, char **ppdata)
772 {
773   /* We must be careful here that we don't return more than the
774      allowed number of data bytes. If this means returning fewer than
775      maxentries then so be it. We assume that the redirector has
776      enough room for the fixed number of parameter bytes it has
777      requested. */
778   int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
779   char *params = *pparams;
780   char *pdata = *ppdata;
781   int16 dptr_num = SVAL(params,0);
782   int maxentries = SVAL(params,2);
783   uint16 info_level = SVAL(params,4);
784   uint32 resume_key = IVAL(params,6);
785   BOOL close_after_request = BITSETW(params+10,0);
786   BOOL close_if_end = BITSETW(params+10,1);
787   BOOL requires_resume_key = BITSETW(params+10,2);
788   BOOL continue_bit = BITSETW(params+10,3);
789   pstring mask;
790   pstring directory;
791   char *p;
792   uint16 dirtype;
793   int numentries = 0;
794   int i, last_name_off=0;
795   BOOL finished = False;
796   BOOL dont_descend = False;
797   BOOL out_of_space = False;
798   int space_remaining;
799
800   *mask = *directory = 0;
801
802   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",
803            dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, 
804            requires_resume_key, resume_key, continue_bit, info_level));
805
806   switch (info_level) 
807     {
808     case 1:
809     case 2:
810     case 3:
811     case 4:
812     case SMB_FIND_FILE_DIRECTORY_INFO:
813     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
814     case SMB_FIND_FILE_NAMES_INFO:
815     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
816       break;
817     default:
818       return(ERROR(ERRDOS,ERRunknownlevel));
819     }
820
821   pdata = *ppdata = Realloc( *ppdata, max_data_bytes + 1024);
822   if(!*ppdata)
823     return(ERROR(ERRDOS,ERRnomem));
824   bzero(pdata,max_data_bytes);
825
826   /* Realloc the params space */
827   params = *pparams = Realloc(*pparams, 6*SIZEOFWORD);
828   if(!params)
829     return(ERROR(ERRDOS,ERRnomem));
830
831   /* Check that the dptr is valid */
832   if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num)))
833     return(ERROR(ERRDOS,ERRnofiles));
834
835   string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
836
837   /* Get the wildcard mask from the dptr */
838   if((p = dptr_wcard(dptr_num))== NULL) {
839     DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
840     return (ERROR(ERRDOS,ERRnofiles));
841   }
842   strcpy(mask, p);
843   strcpy(directory,Connections[cnum].dirpath);
844
845   /* Get the attr mask from the dptr */
846   dirtype = dptr_attr(dptr_num);
847
848   DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%X,%d)\n",
849            dptr_num, mask, dirtype, 
850            Connections[cnum].dirptr,
851            TellDir(Connections[cnum].dirptr)));
852
853   /* We don't need to check for VOL here as this is returned by 
854      a different TRANS2 call. */
855
856   DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
857   if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
858     dont_descend = True;
859     
860   p = pdata;
861   space_remaining = max_data_bytes;
862   out_of_space = False;
863
864   /* If we have a resume key - seek to the correct position. */
865   if(requires_resume_key && !continue_bit)
866     SeekDir(Connections[cnum].dirptr, resume_key);
867
868   for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
869     {
870       /* this is a heuristic to avoid seeking the dirptr except when 
871          absolutely necessary. It allows for a filename of about 40 chars */
872       if (space_remaining < DIRLEN_GUESS && numentries > 0)
873         {
874           out_of_space = True;
875           finished = False;
876         }
877       else
878         {
879           finished = 
880             !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
881                                    requires_resume_key,dont_descend,
882                                    &p,pdata,space_remaining, &out_of_space,
883                                    &last_name_off);
884         }
885
886       if (finished && out_of_space)
887         finished = False;
888
889       if (!finished && !out_of_space)
890         numentries++;
891       space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
892     }
893   
894   /* Check if we can close the dirptr */
895   if(close_after_request || (finished && close_if_end))
896     {
897       dptr_close(dptr_num); /* This frees up the saved mask */
898       DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
899       dptr_num = -1;
900     }
901
902
903   /* Set up the return parameter block */
904   SSVAL(params,0,numentries);
905   SSVAL(params,2,finished);
906   SSVAL(params,4,0); /* Never an EA error */
907   SSVAL(params,6,last_name_off);
908
909   send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
910
911   if ((! *directory) && dptr_path(dptr_num))
912     sprintf(directory,"(%s)",dptr_path(dptr_num));
913
914   DEBUG(3,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
915            timestring(),
916            smb_fn_name(CVAL(inbuf,smb_com)), 
917            mask,directory,cnum,dirtype,numentries));
918
919   return(-1);
920 }
921
922 /****************************************************************************
923   reply to a TRANS2_QFSINFO (query filesystem info)
924 ****************************************************************************/
925 static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
926                         int cnum, char **pparams, char **ppdata)
927 {
928   char *pdata = *ppdata;
929   char *params = *pparams;
930   uint16 info_level = SVAL(params,0);
931   int data_len;
932   struct stat st;
933   char *vname = volume_label(SNUM(cnum));
934   
935   DEBUG(3,("call_trans2qfsinfo: cnum = %d, level = %d\n", cnum, info_level));
936
937   if(sys_stat(".",&st)!=0) {
938     DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
939     return (ERROR(ERRSRV,ERRinvdevice));
940   }
941
942   pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,1024);
943
944   switch (info_level) 
945     {
946     case 1:
947       {
948         int dfree,dsize,bsize;
949         data_len = 18;
950         sys_disk_free(".",&bsize,&dfree,&dsize);        
951         SIVAL(pdata,l1_idFileSystem,st.st_dev);
952         SIVAL(pdata,l1_cSectorUnit,bsize/512);
953         SIVAL(pdata,l1_cUnit,dsize);
954         SIVAL(pdata,l1_cUnitAvail,dfree);
955         SSVAL(pdata,l1_cbSector,512);
956         DEBUG(5,("call_trans2qfsinfo : bsize=%d, id=%x, cSectorUnit=%d, cUnit=%d, cUnitAvail=%d, cbSector=%d\n",
957                  bsize, st.st_dev, bsize/512, dsize, dfree, 512));
958         break;
959     }
960     case 2:
961     { 
962       /* Return volume name */
963       int volname_len = MIN(strlen(vname),11);
964       data_len = l2_vol_szVolLabel + volname_len + 1;
965       put_dos_date2(pdata,l2_vol_fdateCreation,st.st_ctime);
966       SCVAL(pdata,l2_vol_cch,volname_len);
967       StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
968       DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime, volname_len,
969                pdata+l2_vol_szVolLabel));
970       break;
971     }
972     case SMB_QUERY_FS_ATTRIBUTE_INFO:
973       data_len = 12 + 2*strlen(FSTYPE_STRING);
974       SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
975       SIVAL(pdata,4,128); /* Max filename component length */
976       SIVAL(pdata,8,2*strlen(FSTYPE_STRING));
977       PutUniCode(pdata+12,FSTYPE_STRING);
978       break;
979     case SMB_QUERY_FS_LABEL_INFO:
980       data_len = 4 + strlen(vname);
981       SIVAL(pdata,0,strlen(vname));
982       strcpy(pdata+4,vname);      
983       break;
984     case SMB_QUERY_FS_VOLUME_INFO:      
985       data_len = 18 + 2*strlen(vname);
986       SIVAL(pdata,12,2*strlen(vname));
987       PutUniCode(pdata+18,vname);      
988       DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", strlen(vname),
989                vname));
990       break;
991     case SMB_QUERY_FS_SIZE_INFO:
992       {
993         int dfree,dsize,bsize;
994         data_len = 24;
995         sys_disk_free(".",&bsize,&dfree,&dsize);        
996         SIVAL(pdata,0,dsize);
997         SIVAL(pdata,8,dfree);
998         SIVAL(pdata,16,bsize/512);
999         SIVAL(pdata,20,512);
1000       }
1001       break;
1002     case SMB_QUERY_FS_DEVICE_INFO:
1003       data_len = 8;
1004       SIVAL(pdata,0,0); /* dev type */
1005       SIVAL(pdata,4,0); /* characteristics */
1006       break;
1007     default:
1008       return(ERROR(ERRDOS,ERRunknownlevel));
1009     }
1010
1011
1012   send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len);
1013
1014   DEBUG(4,("%s %s info_level =%d\n",timestring(),smb_fn_name(CVAL(inbuf,smb_com)), info_level));
1015
1016   return -1;
1017 }
1018
1019 /****************************************************************************
1020   reply to a TRANS2_SETFSINFO (set filesystem info)
1021 ****************************************************************************/
1022 static int call_trans2setfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
1023                         int cnum, char **pparams, char **ppdata)
1024 {
1025   /* Just say yes we did it - there is nothing that
1026      can be set here so it doesn't matter. */
1027   int outsize;
1028   DEBUG(3,("call_trans2setfsinfo\n"));
1029
1030   if (!CAN_WRITE(cnum))
1031     return(ERROR(ERRSRV,ERRaccess));
1032
1033   outsize = set_message(outbuf,10,0,True);
1034
1035   return outsize;
1036 }
1037
1038 /****************************************************************************
1039   reply to a TRANS2_QFILEINFO (query file info by fileid)
1040 ****************************************************************************/
1041 static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length, 
1042                                     int bufsize,int cnum,
1043                                     char **pparams,char **ppdata,
1044                                     int total_data)
1045 {
1046   char *params = *pparams;
1047   char *pdata = *ppdata;
1048   uint16 tran_call = SVAL(inbuf, smb_setup0);
1049   uint16 info_level;
1050   int mode=0;
1051   int size=0;
1052   unsigned int data_size;
1053   struct stat sbuf;
1054   pstring fname1;
1055   char *fname;
1056   char *p;
1057   int l,pos;
1058   BOOL bad_path = False;
1059
1060   if (tran_call == TRANSACT2_QFILEINFO) {
1061     int16 fnum = SVALS(params,0);
1062     info_level = SVAL(params,2);
1063
1064     CHECK_FNUM(fnum,cnum);
1065     CHECK_ERROR(fnum);
1066
1067     fname = Files[fnum].name;
1068     if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
1069       DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno)));
1070       return(UNIXERROR(ERRDOS,ERRbadfid));
1071     }
1072     pos = lseek(Files[fnum].fd_ptr->fd,0,SEEK_CUR);
1073   } else {
1074     /* qpathinfo */
1075     info_level = SVAL(params,0);
1076     fname = &fname1[0];
1077     pstrcpy(fname,&params[6]);
1078     unix_convert(fname,cnum,0,&bad_path);
1079     if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
1080       DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
1081       if((errno == ENOENT) && bad_path)
1082       {
1083         unix_ERR_class = ERRDOS;
1084         unix_ERR_code = ERRbadpath;
1085       }
1086       return(UNIXERROR(ERRDOS,ERRbadpath));
1087     }
1088     pos = 0;
1089   }
1090
1091
1092   DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
1093            fname,info_level,tran_call,total_data));
1094
1095   p = strrchr(fname,'/'); 
1096   if (!p) 
1097     p = fname;
1098   else
1099     p++;
1100   l = strlen(p);  
1101   mode = dos_mode(cnum,fname,&sbuf);
1102   size = sbuf.st_size;
1103   if (mode & aDIR) size = 0;
1104   
1105   params = *pparams = Realloc(*pparams,2); bzero(params,2);
1106   data_size = 1024;
1107   pdata = *ppdata = Realloc(*ppdata, data_size); 
1108
1109   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1110     /* uggh, EAs for OS2 */
1111     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1112     return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
1113   }
1114
1115   bzero(pdata,data_size);
1116
1117   switch (info_level) 
1118     {
1119     case SMB_INFO_STANDARD:
1120     case SMB_INFO_QUERY_EA_SIZE:
1121       data_size = (info_level==1?22:26);
1122       put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime); /* create = inode mod */
1123       put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); /* access time */
1124       put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
1125       SIVAL(pdata,l1_cbFile,size);
1126       SIVAL(pdata,l1_cbFileAlloc,ROUNDUP(size,1024));
1127       SSVAL(pdata,l1_attrFile,mode);
1128       SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
1129       break;
1130
1131     case SMB_INFO_QUERY_EAS_FROM_LIST:
1132       data_size = 24;
1133       put_dos_date2(pdata,0,sbuf.st_ctime); /* create time = inode mod time */
1134       put_dos_date2(pdata,4,sbuf.st_atime);
1135       put_dos_date2(pdata,8,sbuf.st_mtime);
1136       SIVAL(pdata,12,size);
1137       SIVAL(pdata,16,ROUNDUP(size,1024));
1138       SIVAL(pdata,20,mode);
1139       break;
1140
1141     case SMB_INFO_QUERY_ALL_EAS:
1142       data_size = 4;
1143       SIVAL(pdata,0,data_size);
1144       break;
1145
1146     case 6:
1147       return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */      
1148
1149     case SMB_QUERY_FILE_BASIC_INFO:
1150       data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
1151       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1152       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1153       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1154       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1155       SIVAL(pdata,32,mode);
1156
1157       DEBUG(5,("SMB_QFBI - "));
1158       DEBUG(5,("create: %s ", ctime(&sbuf.st_ctime)));
1159       DEBUG(5,("access: %s ", ctime(&sbuf.st_atime)));
1160       DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
1161       DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
1162       DEBUG(5,("mode: %x\n", mode));
1163
1164       break;
1165
1166     case SMB_QUERY_FILE_STANDARD_INFO:
1167       data_size = 22;
1168       SIVAL(pdata,0,size);
1169       SIVAL(pdata,8,size);
1170       SIVAL(pdata,16,sbuf.st_nlink);
1171       CVAL(pdata,20) = 0;
1172       CVAL(pdata,21) = (mode&aDIR)?1:0;
1173       break;
1174
1175     case SMB_QUERY_FILE_EA_INFO:
1176       data_size = 4;
1177       break;
1178
1179     case SMB_QUERY_FILE_NAME_INFO:
1180     case SMB_QUERY_FILE_ALT_NAME_INFO:
1181       data_size = 4 + l;
1182       SIVAL(pdata,0,l);
1183       pstrcpy(pdata+4,fname);
1184       break;
1185     case SMB_QUERY_FILE_ALLOCATION_INFO:
1186     case SMB_QUERY_FILE_END_OF_FILEINFO:
1187       data_size = 8;
1188       SIVAL(pdata,0,size);
1189       break;
1190
1191     case SMB_QUERY_FILE_ALL_INFO:
1192       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1193       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1194       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1195       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1196       SIVAL(pdata,32,mode);
1197       pdata += 40;
1198       SIVAL(pdata,0,size);
1199       SIVAL(pdata,8,size);
1200       SIVAL(pdata,16,sbuf.st_nlink);
1201       CVAL(pdata,20) = 0;
1202       CVAL(pdata,21) = (mode&aDIR)?1:0;
1203       pdata += 24;
1204       pdata += 8; /* index number */
1205       pdata += 4; /* EA info */
1206       if (mode & aRONLY)
1207         SIVAL(pdata,0,0xA9);
1208       else
1209         SIVAL(pdata,0,0xd01BF);
1210       pdata += 4;
1211       SIVAL(pdata,0,pos); /* current offset */
1212       pdata += 8;
1213       SIVAL(pdata,0,mode); /* is this the right sort of mode info? */
1214       pdata += 4;
1215       pdata += 4; /* alignment */
1216       SIVAL(pdata,0,l);
1217       pstrcpy(pdata+4,fname);
1218       pdata += 4 + l;
1219       data_size = PTR_DIFF(pdata,(*ppdata));
1220       break;
1221
1222     case SMB_QUERY_FILE_STREAM_INFO:
1223       data_size = 24 + l;
1224       SIVAL(pdata,0,pos);
1225       SIVAL(pdata,4,size);
1226       SIVAL(pdata,12,size);
1227       SIVAL(pdata,20,l);        
1228       pstrcpy(pdata+24,fname);
1229       break;
1230     default:
1231       return(ERROR(ERRDOS,ERRunknownlevel));
1232     }
1233
1234   send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size);
1235
1236   return(-1);
1237 }
1238
1239 /****************************************************************************
1240   reply to a TRANS2_SETFILEINFO (set file info by fileid)
1241 ****************************************************************************/
1242 static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length, 
1243                                       int bufsize, int cnum, char **pparams, 
1244                                       char **ppdata, int total_data)
1245 {
1246   char *params = *pparams;
1247   char *pdata = *ppdata;
1248   uint16 tran_call = SVAL(inbuf, smb_setup0);
1249   uint16 info_level;
1250   int mode=0;
1251   int size=0;
1252   struct utimbuf tvs;
1253   struct stat st;
1254   pstring fname1;
1255   char *fname;
1256   int fd = -1;
1257   BOOL bad_path = False;
1258
1259   if (!CAN_WRITE(cnum))
1260     return(ERROR(ERRSRV,ERRaccess));
1261
1262   if (tran_call == TRANSACT2_SETFILEINFO) {
1263     int16 fnum = SVALS(params,0);
1264     info_level = SVAL(params,2);    
1265
1266     CHECK_FNUM(fnum,cnum);
1267     CHECK_ERROR(fnum);
1268
1269     fname = Files[fnum].name;
1270     fd = Files[fnum].fd_ptr->fd;
1271
1272     if(fstat(fd,&st)!=0) {
1273       DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
1274       return(ERROR(ERRDOS,ERRbadpath));
1275     }
1276   } else {
1277     /* set path info */
1278     info_level = SVAL(params,0);    
1279     fname = fname1;
1280     pstrcpy(fname,&params[6]);
1281     unix_convert(fname,cnum,0,&bad_path);
1282     if(!check_name(fname, cnum))
1283     {
1284       if((errno == ENOENT) && bad_path)
1285       {
1286         unix_ERR_class = ERRDOS;
1287         unix_ERR_code = ERRbadpath;
1288       }
1289       return(UNIXERROR(ERRDOS,ERRbadpath));
1290     }
1291  
1292     if(sys_stat(fname,&st)!=0) {
1293       DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
1294       if((errno == ENOENT) && bad_path)
1295       {
1296         unix_ERR_class = ERRDOS;
1297         unix_ERR_code = ERRbadpath;
1298       }
1299       return(UNIXERROR(ERRDOS,ERRbadpath));
1300     }    
1301   }
1302
1303   DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
1304            tran_call,fname,info_level,total_data));
1305
1306   /* Realloc the parameter and data sizes */
1307   params = *pparams = Realloc(*pparams,2); SSVAL(params,0,0);
1308   if(params == NULL)
1309     return(ERROR(ERRDOS,ERRnomem));
1310
1311   size = st.st_size;
1312   tvs.modtime = st.st_mtime;
1313   tvs.actime = st.st_atime;
1314   mode = dos_mode(cnum,fname,&st);
1315
1316   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1317     /* uggh, EAs for OS2 */
1318     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1319     return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
1320   }
1321
1322   switch (info_level)
1323   {
1324     case SMB_INFO_STANDARD:
1325     case SMB_INFO_QUERY_EA_SIZE:
1326     {
1327       /* access time */
1328       tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
1329
1330       /* write time */
1331       tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
1332
1333       mode = SVAL(pdata,l1_attrFile);
1334       size = IVAL(pdata,l1_cbFile);
1335       break;
1336     }
1337
1338     /* XXXX um, i don't think this is right.
1339        it's also not in the cifs6.txt spec.
1340      */
1341     case SMB_INFO_QUERY_EAS_FROM_LIST:
1342       tvs.actime = make_unix_date2(pdata+8);
1343       tvs.modtime = make_unix_date2(pdata+12);
1344       size = IVAL(pdata,16);
1345       mode = IVAL(pdata,24);
1346       break;
1347
1348     /* XXXX nor this.  not in cifs6.txt, either. */
1349     case SMB_INFO_QUERY_ALL_EAS:
1350       tvs.actime = make_unix_date2(pdata+8);
1351       tvs.modtime = make_unix_date2(pdata+12);
1352       size = IVAL(pdata,16);
1353       mode = IVAL(pdata,24);
1354       break;
1355
1356     case SMB_SET_FILE_BASIC_INFO:
1357     {
1358       /* Ignore create time at offset pdata. */
1359
1360       /* access time */
1361       tvs.actime = interpret_long_date(pdata+8);
1362
1363       /* write time + changed time, combined. */
1364       tvs.modtime=MAX(interpret_long_date(pdata+16),
1365                       interpret_long_date(pdata+24));
1366
1367 #if 0 /* Needs more testing... */
1368       /* Test from Luke to prevent Win95 from
1369          setting incorrect values here.
1370        */
1371       if (tvs.actime < tvs.modtime)
1372         return(ERROR(ERRDOS,ERRnoaccess));
1373 #endif /* Needs more testing... */
1374
1375       /* attributes */
1376       mode = IVAL(pdata,32);
1377       break;
1378     }
1379
1380     case SMB_SET_FILE_END_OF_FILE_INFO:
1381     {
1382       if (IVAL(pdata,4) != 0)   /* more than 32 bits? */
1383          return(ERROR(ERRDOS,ERRunknownlevel));
1384       size = IVAL(pdata,0);
1385       break;
1386     }
1387
1388     case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
1389     case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
1390     default:
1391     {
1392       return(ERROR(ERRDOS,ERRunknownlevel));
1393     }
1394   }
1395
1396   DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
1397   DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
1398   DEBUG(6,("size: %x "   , size));
1399   DEBUG(6,("mode: %x\n"  , mode));
1400
1401   /* get some defaults (no modifications) if any info is zero. */
1402   if (!tvs.actime) tvs.actime = st.st_atime;
1403   if (!tvs.modtime) tvs.modtime = st.st_mtime;
1404   if (!size) size = st.st_size;
1405
1406   /* Try and set the times, size and mode of this file -
1407      if they are different from the current values
1408    */
1409   if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
1410   {
1411     if(sys_utime(fname, &tvs)!=0)
1412     {
1413       return(ERROR(ERRDOS,ERRnoaccess));
1414     }
1415   }
1416
1417   /* check the mode isn't different, before changing it */
1418   if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL))
1419   {
1420     DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
1421     return(ERROR(ERRDOS,ERRnoaccess));
1422   }
1423
1424   if(size != st.st_size)
1425   {
1426     if (fd == -1)
1427     {
1428       fd = sys_open(fname,O_RDWR,0);
1429       if (fd == -1)
1430       {
1431         return(ERROR(ERRDOS,ERRbadpath));
1432       }
1433       set_filelen(fd, size);
1434       close(fd);
1435     }
1436     else
1437     {
1438       set_filelen(fd, size);
1439     }
1440   }
1441
1442   SSVAL(params,0,0);
1443
1444   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1445   
1446   return(-1);
1447 }
1448
1449 /****************************************************************************
1450   reply to a TRANS2_MKDIR (make directory with extended attributes).
1451 ****************************************************************************/
1452 static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
1453                         int cnum, char **pparams, char **ppdata)
1454 {
1455   char *params = *pparams;
1456   pstring directory;
1457   int ret = -1;
1458   BOOL bad_path = False;
1459
1460   if (!CAN_WRITE(cnum))
1461     return(ERROR(ERRSRV,ERRaccess));
1462
1463   pstrcpy(directory, &params[4]);
1464
1465   DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
1466
1467   unix_convert(directory,cnum,0,&bad_path);
1468   if (check_name(directory,cnum))
1469     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
1470   
1471   if(ret < 0)
1472     {
1473       DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
1474       if((errno == ENOENT) && bad_path)
1475       {
1476         unix_ERR_class = ERRDOS;
1477         unix_ERR_code = ERRbadpath;
1478       }
1479       return(UNIXERROR(ERRDOS,ERRnoaccess));
1480     }
1481
1482   /* Realloc the parameter and data sizes */
1483   params = *pparams = Realloc(*pparams,2);
1484   if(params == NULL)
1485     return(ERROR(ERRDOS,ERRnomem));
1486
1487   SSVAL(params,0,0);
1488
1489   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1490   
1491   return(-1);
1492 }
1493
1494 /****************************************************************************
1495   reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes)
1496   We don't actually do this - we just send a null response.
1497 ****************************************************************************/
1498 static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int bufsize,
1499                         int cnum, char **pparams, char **ppdata)
1500 {
1501   static uint16 fnf_handle = 257;
1502   char *params = *pparams;
1503   uint16 info_level = SVAL(params,4);
1504
1505   DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
1506
1507   switch (info_level) 
1508     {
1509     case 1:
1510     case 2:
1511       break;
1512     default:
1513       return(ERROR(ERRDOS,ERRunknownlevel));
1514     }
1515
1516   /* Realloc the parameter and data sizes */
1517   params = *pparams = Realloc(*pparams,6);
1518   if(params == NULL)
1519     return(ERROR(ERRDOS,ERRnomem));
1520
1521   SSVAL(params,0,fnf_handle);
1522   SSVAL(params,2,0); /* No changes */
1523   SSVAL(params,4,0); /* No EA errors */
1524
1525   fnf_handle++;
1526
1527   if(fnf_handle == 0)
1528     fnf_handle = 257;
1529
1530   send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0);
1531   
1532   return(-1);
1533 }
1534
1535 /****************************************************************************
1536   reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for 
1537   changes). Currently this does nothing.
1538 ****************************************************************************/
1539 static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int bufsize,
1540                         int cnum, char **pparams, char **ppdata)
1541 {
1542   char *params = *pparams;
1543
1544   DEBUG(3,("call_trans2findnotifynext\n"));
1545
1546   /* Realloc the parameter and data sizes */
1547   params = *pparams = Realloc(*pparams,4);
1548   if(params == NULL)
1549     return(ERROR(ERRDOS,ERRnomem));
1550
1551   SSVAL(params,0,0); /* No changes */
1552   SSVAL(params,2,0); /* No EA errors */
1553
1554   send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
1555   
1556   return(-1);
1557 }
1558
1559 /****************************************************************************
1560   reply to a SMBfindclose (stop trans2 directory search)
1561 ****************************************************************************/
1562 int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
1563 {
1564   int cnum;
1565   int outsize = 0;
1566   int16 dptr_num=SVALS(inbuf,smb_vwv0);
1567
1568   cnum = SVAL(inbuf,smb_tid);
1569
1570   DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1571
1572   dptr_close(dptr_num);
1573
1574   outsize = set_message(outbuf,0,0,True);
1575
1576   DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1577
1578   return(outsize);
1579 }
1580
1581 /****************************************************************************
1582   reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search)
1583 ****************************************************************************/
1584 int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize)
1585 {
1586   int cnum;
1587   int outsize = 0;
1588   int dptr_num= -1;
1589
1590   cnum = SVAL(inbuf,smb_tid);
1591   dptr_num = SVAL(inbuf,smb_vwv0);
1592
1593   DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1594
1595   /* We never give out valid handles for a 
1596      findnotifyfirst - so any dptr_num is ok here. 
1597      Just ignore it. */
1598
1599   outsize = set_message(outbuf,0,0,True);
1600
1601   DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1602
1603   return(outsize);
1604 }
1605
1606
1607 /****************************************************************************
1608   reply to a SMBtranss2 - just ignore it!
1609 ****************************************************************************/
1610 int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize)
1611 {
1612   DEBUG(4,("Ignoring transs2 of length %d\n",length));
1613   return(-1);
1614 }
1615
1616 /****************************************************************************
1617   reply to a SMBtrans2
1618 ****************************************************************************/
1619 int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
1620 {
1621   int outsize = 0;
1622   int cnum = SVAL(inbuf,smb_tid);
1623   unsigned int total_params = SVAL(inbuf, smb_tpscnt);
1624   unsigned int total_data =SVAL(inbuf, smb_tdscnt);
1625 #if 0
1626   unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
1627   unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
1628   unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
1629   BOOL close_tid = BITSETW(inbuf+smb_flags,0);
1630   BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
1631   int32 timeout = IVALS(inbuf,smb_timeout);
1632 #endif
1633   unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
1634   unsigned int tran_call = SVAL(inbuf, smb_setup0);
1635   char *params = NULL, *data = NULL;
1636   int num_params, num_params_sofar, num_data, num_data_sofar;
1637
1638   outsize = set_message(outbuf,0,0,True);
1639
1640   /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
1641      is so as a sanity check */
1642   if(suwcnt != 1 )
1643     {
1644       DEBUG(2,("Invalid smb_sucnt in trans2 call\n"));
1645       return(ERROR(ERRSRV,ERRerror));
1646     }
1647     
1648   /* Allocate the space for the maximum needed parameters and data */
1649   if (total_params > 0)
1650     params = (char *)malloc(total_params);
1651   if (total_data > 0)
1652     data = (char *)malloc(total_data);
1653   
1654   if ((total_params && !params)  || (total_data && !data))
1655     {
1656       DEBUG(2,("Out of memory in reply_trans2\n"));
1657       return(ERROR(ERRDOS,ERRnomem));
1658     }
1659
1660   /* Copy the param and data bytes sent with this request into
1661      the params buffer */
1662   num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
1663   num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
1664
1665   if (num_params > total_params || num_data > total_data)
1666           exit_server("invalid params in reply_trans2");
1667
1668   memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
1669   memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
1670
1671   if(num_data_sofar < total_data || num_params_sofar < total_params)
1672     {
1673     /* We need to send an interim response then receive the rest
1674        of the parameter/data bytes */
1675       outsize = set_message(outbuf,0,0,True);
1676       send_smb(Client,outbuf);
1677
1678       while( num_data_sofar < total_data || num_params_sofar < total_params)
1679         {
1680           if(!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
1681              CVAL(inbuf, smb_com) != SMBtranss2)
1682             {
1683               outsize = set_message(outbuf,0,0,True);
1684               DEBUG(2,("Invalid secondary trans2 packet\n"));
1685               free(params);
1686               free(data);
1687               return(ERROR(ERRSRV,ERRerror));
1688             }
1689       
1690           /* Revise total_params and total_data in case they have changed downwards */
1691           total_params = SVAL(inbuf, smb_tpscnt);
1692           total_data = SVAL(inbuf, smb_tdscnt);
1693           num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
1694           num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
1695           if (num_params_sofar > total_params || num_data_sofar > total_data)
1696                   exit_server("data overflow in trans2");
1697
1698           memcpy( &params[ SVAL(inbuf, smb_spsdisp)], 
1699                  smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
1700           memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
1701                  smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
1702         }
1703     }
1704
1705   if (Protocol >= PROTOCOL_NT1) {
1706     uint16 flg2 = SVAL(outbuf,smb_flg2);
1707     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1708   }
1709
1710   /* Now we must call the relevant TRANS2 function */
1711   switch(tran_call) 
1712     {
1713     case TRANSACT2_OPEN:
1714       outsize = call_trans2open(inbuf, outbuf, bufsize, cnum, &params, &data);
1715       break;
1716     case TRANSACT2_FINDFIRST:
1717       outsize = call_trans2findfirst(inbuf, outbuf, bufsize, cnum, &params, &data);
1718       break;
1719     case TRANSACT2_FINDNEXT:
1720       outsize = call_trans2findnext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1721       break;
1722     case TRANSACT2_QFSINFO:
1723       outsize = call_trans2qfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1724       break;
1725     case TRANSACT2_SETFSINFO:
1726       outsize = call_trans2setfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1727       break;
1728     case TRANSACT2_QPATHINFO:
1729     case TRANSACT2_QFILEINFO:
1730       outsize = call_trans2qfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1731       break;
1732     case TRANSACT2_SETPATHINFO:
1733     case TRANSACT2_SETFILEINFO:
1734       outsize = call_trans2setfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1735       break;
1736     case TRANSACT2_FINDNOTIFYFIRST:
1737       outsize = call_trans2findnotifyfirst(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1738       break;
1739     case TRANSACT2_FINDNOTIFYNEXT:
1740       outsize = call_trans2findnotifynext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1741       break;
1742     case TRANSACT2_MKDIR:
1743       outsize = call_trans2mkdir(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1744       break;
1745     default:
1746       /* Error in request */
1747       DEBUG(2,("%s Unknown request %d in trans2 call\n",timestring(), tran_call));
1748       if(params)
1749         free(params);
1750       if(data)
1751         free(data);
1752       return (ERROR(ERRSRV,ERRerror));
1753     }
1754
1755   /* As we do not know how many data packets will need to be
1756      returned here the various call_trans2xxxx calls
1757      must send their own. Thus a call_trans2xxx routine only
1758      returns a value other than -1 when it wants to send
1759      an error packet. 
1760   */
1761
1762   if(params)
1763     free(params);
1764   if(data)
1765     free(data);
1766   return outsize; /* If a correct response was needed the call_trans2xxx 
1767                      calls have already sent it. If outsize != -1 then it is
1768                      returning an error packet. */
1769 }