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