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