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