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