Changes to allow Samba to return the same error code as Windows NT.
[Samba.git] / source / smbd / trans2.c
blob9a48fb3ded20b72f6e46c10b63d42576537cee2d
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SMB transaction2 handling
5 Copyright (C) Jeremy Allison 1994-1997
7 Extensively modified by Andrew Tridgell, 1995
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.
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.
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.
24 #include "includes.h"
25 #include "trans2.h"
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;
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)
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 */
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;
58 /* Initially set the wcnt area to be 10 - this is true for all
59 trans2 replies */
60 set_message(outbuf,10,0,True);
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)
66 send_smb(Client,outbuf);
67 return 0;
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);
78 while( params_to_send || data_to_send)
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);
85 set_message(outbuf, 10, total_sent_thistime, True);
87 /* Set total params and data to be sent */
88 SSVAL(outbuf,smb_tprcnt,paramsize);
89 SSVAL(outbuf,smb_tdrcnt,datasize);
91 /* Calculate how many parameters and data we can fit into
92 this packet. Parameters get precedence */
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);
98 SSVAL(outbuf,smb_prcnt, params_sent_thistime);
99 if(params_sent_thistime == 0)
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);
113 SSVAL(outbuf,smb_drcnt, data_sent_thistime);
114 if(data_sent_thistime == 0)
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);
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);
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));
138 /* Send the packet */
139 send_smb(Client,outbuf);
141 pp += params_sent_thistime;
142 pd += data_sent_thistime;
144 params_to_send -= params_sent_thistime;
145 data_to_send -= data_sent_thistime;
147 /* Sanity check */
148 if(params_to_send < 0 || data_to_send < 0)
150 DEBUG(2,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
151 params_to_send, data_to_send));
152 return -1;
156 return 0;
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)
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;
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;
189 StrnCpy(fname,pname,namelen);
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));
194 /* XXXX we need to handle passed times, sattr and flags */
196 unix_convert(fname,cnum,0,&bad_path);
198 fnum = find_free_file();
199 if (fnum < 0)
200 return(ERROR(ERRSRV,ERRnofids));
202 if (!check_name(fname,cnum))
204 if((errno == ENOENT) && bad_path)
206 unix_ERR_class = ERRDOS;
207 unix_ERR_code = ERRbadpath;
209 return(UNIXERROR(ERRDOS,ERRnoaccess));
212 unixmode = unix_mode(cnum,open_attr | aARCH);
215 open_file_shared(fnum,cnum,fname,open_mode,open_ofun,unixmode,
216 &rmode,&smb_action);
218 if (!Files[fnum].open)
220 if((errno == ENOENT) && bad_path)
222 unix_ERR_class = ERRDOS;
223 unix_ERR_code = ERRbadpath;
225 return(UNIXERROR(ERRDOS,ERRnoaccess));
228 if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
229 close_file(fnum);
230 return(ERROR(ERRDOS,ERRnoaccess));
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));
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));
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);
254 if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
255 smb_action |= (1<<15);
258 SSVAL(params,18,smb_action);
259 SIVAL(params,20,inode);
261 /* Send the required number of replies */
262 send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0);
264 return -1;
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)
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] != '/');
297 *fname = 0;
298 *out_of_space = False;
300 if (!Connections[cnum].dirptr)
301 return(False);
303 p = strrchr(path_mask,'/');
304 if(p != NULL)
306 if(p[1] == '\0')
307 strcpy(mask,"*.*");
308 else
309 strcpy(mask, p+1);
311 else
312 strcpy(mask, path_mask);
314 while (!found)
316 /* Needed if we run out of space */
317 prev_dirpos = TellDir(Connections[cnum].dirptr);
318 dname = ReadDirName(Connections[cnum].dirptr);
320 reskey = TellDir(Connections[cnum].dirptr);
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)));
325 if (!dname)
326 return(False);
328 matched = False;
330 strcpy(fname,dname);
332 if(mask_match(fname, mask, case_sensitive, True))
334 BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
335 if (dont_descend && !isdots)
336 continue;
338 if (isrootdir && isdots)
339 continue;
341 strcpy(pathreal,Connections[cnum].dirpath);
342 if(needslash)
343 strcat(pathreal,"/");
344 strcat(pathreal,fname);
345 if (sys_stat(pathreal,&sbuf) != 0)
347 DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno)));
348 continue;
351 mode = dos_mode(cnum,pathreal,&sbuf);
353 if (!dir_check_ftype(cnum,mode,&sbuf,dirtype)) {
354 DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
355 continue;
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;
365 DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
367 found = True;
373 p = pdata;
374 nameptr = p;
376 name_map_mangle(fname,False,SNUM(cnum));
378 nt_extmode = mode ? mode : NT_FILE_ATTRIBUTE_NORMAL;
380 switch (info_level)
382 case 1:
383 if(requires_resume_key) {
384 SIVAL(p,0,reskey);
385 p += 4;
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;
399 case 2:
400 /* info_level 2 */
401 if(requires_resume_key) {
402 SIVAL(p,0,reskey);
403 p += 4;
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;
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;
433 case 4:
434 if(requires_resume_key) {
435 SIVAL(p,0,reskey);
436 p += 4;
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;
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;
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;
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;
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;
526 default:
527 return(False);
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 */
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);
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)
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;
579 *directory = *mask = 0;
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));
585 switch (info_level)
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));
600 strcpy(directory, params + 12); /* Complete directory path with
601 wildcard mask appended */
603 DEBUG(5,("path=%s\n",directory));
605 unix_convert(directory,cnum,0,&bad_path);
606 if(!check_name(directory,cnum)) {
607 if((errno == ENOENT) && bad_path)
609 unix_ERR_class = ERRDOS;
610 unix_ERR_code = ERRbadpath;
612 return(ERROR(ERRDOS,ERRbadpath));
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;
624 DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
626 pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
627 if(!*ppdata)
628 return(ERROR(ERRDOS,ERRnomem));
629 bzero(pdata,max_data_bytes);
631 /* Realloc the params space */
632 params = *pparams = Realloc(*pparams, 10);
633 if(params == NULL)
634 return(ERROR(ERRDOS,ERRnomem));
636 dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid));
637 if (dptr_num < 0)
639 if(dptr_num == -2)
641 if((errno == ENOENT) && bad_path)
643 unix_ERR_class = ERRDOS;
644 unix_ERR_code = ERRbadpath;
646 return (UNIXERROR(ERRDOS,ERRbadpath));
648 return(ERROR(ERRDOS,ERRbadpath));
651 /* convert the formatted masks */
653 p = mask;
654 while (*p) {
655 if (*p == '<') *p = '*';
656 if (*p == '>') *p = '?';
657 if (*p == '"') *p = '.';
658 p++;
662 /* a special case for 16 bit apps */
663 if (strequal(mask,"????????.???")) strcpy(mask,"*");
665 /* handle broken clients that send us old 8.3 format */
666 string_sub(mask,"????????","*");
667 string_sub(mask,".???",".*");
669 /* Save the wildcard match and attribs we are using on this directory -
670 needed as lanman2 assumes these are being saved between calls */
672 if(!(wcard = strdup(mask))) {
673 dptr_close(dptr_num);
674 return(ERROR(ERRDOS,ERRnomem));
677 dptr_set_wcard(dptr_num, wcard);
678 dptr_set_attr(dptr_num, dirtype);
680 DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
682 /* We don't need to check for VOL here as this is returned by
683 a different TRANS2 call. */
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;
690 p = pdata;
691 space_remaining = max_data_bytes;
692 out_of_space = False;
694 for (i=0;(i<maxentries) && !finished && !out_of_space;i++)
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)
701 out_of_space = True;
702 finished = False;
704 else
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);
713 if (finished && out_of_space)
714 finished = False;
716 if (!finished && !out_of_space)
717 numentries++;
718 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
721 /* Check if we can close the dirptr */
722 if(close_after_first || (finished && close_if_end))
724 dptr_close(dptr_num);
725 DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
726 dptr_num = -1;
729 /* At this point pdata points to numentries directory entries. */
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);
738 send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
740 if ((! *directory) && dptr_path(dptr_num))
741 sprintf(directory,"(%s)",dptr_path(dptr_num));
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));
748 return(-1);
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)
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;
785 *mask = *directory = 0;
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));
791 switch (info_level)
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));
806 pdata = *ppdata = Realloc( *ppdata, max_data_bytes + 1024);
807 if(!*ppdata)
808 return(ERROR(ERRDOS,ERRnomem));
809 bzero(pdata,max_data_bytes);
811 /* Realloc the params space */
812 params = *pparams = Realloc(*pparams, 6*SIZEOFWORD);
813 if(!params)
814 return(ERROR(ERRDOS,ERRnomem));
816 /* Check that the dptr is valid */
817 if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num)))
818 return(ERROR(ERRDOS,ERRnofiles));
820 string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
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));
827 strcpy(mask, p);
828 strcpy(directory,Connections[cnum].dirpath);
830 /* Get the attr mask from the dptr */
831 dirtype = dptr_attr(dptr_num);
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)));
838 /* We don't need to check for VOL here as this is returned by
839 a different TRANS2 call. */
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;
845 p = pdata;
846 space_remaining = max_data_bytes;
847 out_of_space = False;
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);
853 for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
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)
859 out_of_space = True;
860 finished = False;
862 else
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);
871 if (finished && out_of_space)
872 finished = False;
874 if (!finished && !out_of_space)
875 numentries++;
876 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
879 /* Check if we can close the dirptr */
880 if(close_after_request || (finished && close_if_end))
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;
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);
894 send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
896 if ((! *directory) && dptr_path(dptr_num))
897 sprintf(directory,"(%s)",dptr_path(dptr_num));
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));
904 return(-1);
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)
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));
920 DEBUG(3,("call_trans2qfsinfo: cnum = %d, level = %d\n", cnum, info_level));
922 if(sys_stat(".",&st)!=0) {
923 DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
924 return (ERROR(ERRSRV,ERRinvdevice));
927 pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,1024);
929 switch (info_level)
931 case 1:
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;
945 case 2:
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;
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:
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);
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));
997 send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len);
999 DEBUG(4,("%s %s info_level =%d\n",timestring(),smb_fn_name(CVAL(inbuf,smb_com)), info_level));
1001 return -1;
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)
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"));
1015 if (!CAN_WRITE(cnum))
1016 return(ERROR(ERRSRV,ERRaccess));
1018 outsize = set_message(outbuf,10,0,True);
1020 return outsize;
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)
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;
1045 if (tran_call == TRANSACT2_QFILEINFO) {
1046 int16 fnum = SVALS(params,0);
1047 info_level = SVAL(params,2);
1049 CHECK_FNUM(fnum,cnum);
1050 CHECK_ERROR(fnum);
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));
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)
1068 unix_ERR_class = ERRDOS;
1069 unix_ERR_code = ERRbadpath;
1071 return(UNIXERROR(ERRDOS,ERRbadpath));
1073 pos = 0;
1077 DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
1078 fname,info_level,tran_call,total_data));
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;
1090 params = *pparams = Realloc(*pparams,2); bzero(params,2);
1091 data_size = 1024;
1092 pdata = *ppdata = Realloc(*ppdata, data_size);
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
1106 bzero(pdata,data_size);
1108 switch (info_level)
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;
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;
1132 case SMB_INFO_QUERY_ALL_EAS:
1133 data_size = 4;
1134 SIVAL(pdata,0,data_size);
1135 break;
1137 case 6:
1138 return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */
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);
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));
1155 break;
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;
1166 case SMB_QUERY_FILE_EA_INFO:
1167 data_size = 4;
1168 break;
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;
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;
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));
1225 send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size);
1227 return(-1);
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)
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;
1250 if (!CAN_WRITE(cnum))
1251 return(ERROR(ERRSRV,ERRaccess));
1253 if (tran_call == TRANSACT2_SETFILEINFO) {
1254 int16 fnum = SVALS(params,0);
1255 info_level = SVAL(params,2);
1257 CHECK_FNUM(fnum,cnum);
1258 CHECK_ERROR(fnum);
1260 fname = Files[fnum].name;
1261 fd = Files[fnum].fd_ptr->fd;
1263 if(fstat(fd,&st)!=0) {
1264 DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
1265 return(ERROR(ERRDOS,ERRbadpath));
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))
1275 if((errno == ENOENT) && bad_path)
1277 unix_ERR_class = ERRDOS;
1278 unix_ERR_code = ERRbadpath;
1280 return(UNIXERROR(ERRDOS,ERRbadpath));
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)
1287 unix_ERR_class = ERRDOS;
1288 unix_ERR_code = ERRbadpath;
1290 return(UNIXERROR(ERRDOS,ERRbadpath));
1294 DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
1295 tran_call,fname,info_level,total_data));
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));
1302 size = st.st_size;
1303 tvs.modtime = st.st_mtime;
1304 tvs.actime = st.st_atime;
1305 mode = dos_mode(cnum,fname,&st);
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);
1312 send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1314 return(-1);
1317 switch (info_level)
1319 case SMB_INFO_STANDARD:
1320 case SMB_INFO_QUERY_EA_SIZE:
1322 /* access time */
1323 tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
1325 /* write time */
1326 tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
1328 mode = SVAL(pdata,l1_attrFile);
1329 size = IVAL(pdata,l1_cbFile);
1330 break;
1333 /* XXXX um, i don't think this is right.
1334 it's also not in the cifs6.txt spec.
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;
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;
1351 case SMB_SET_FILE_BASIC_INFO:
1353 /* Ignore create time at offset pdata. */
1355 /* access time */
1356 tvs.actime = interpret_long_date(pdata+8);
1358 /* write time + changed time, combined. */
1359 tvs.modtime=MAX(interpret_long_date(pdata+16),
1360 interpret_long_date(pdata+24));
1362 /* attributes */
1363 mode = IVAL(pdata,32);
1364 break;
1367 case SMB_SET_FILE_END_OF_FILE_INFO:
1369 if (IVAL(pdata,4) != 0) /* more than 32 bits? */
1370 return(ERROR(ERRDOS,ERRunknownlevel));
1371 size = IVAL(pdata,0);
1372 break;
1375 case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
1376 case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
1377 default:
1379 return(ERROR(ERRDOS,ERRunknownlevel));
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));
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;
1393 /* Try and set the times, size and mode of this file -
1394 if they are different from the current values
1396 if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
1398 if(sys_utime(fname, &tvs)!=0)
1400 return(ERROR(ERRDOS,ERRnoaccess));
1404 /* check the mode isn't different, before changing it */
1405 if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL))
1407 DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
1408 return(ERROR(ERRDOS,ERRnoaccess));
1411 if(size != st.st_size)
1413 if (fd == -1)
1415 fd = sys_open(fname,O_RDWR,0);
1416 if (fd == -1)
1418 return(ERROR(ERRDOS,ERRbadpath));
1420 set_filelen(fd, size);
1421 close(fd);
1423 else
1425 set_filelen(fd, size);
1429 SSVAL(params,0,0);
1431 send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1433 return(-1);
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)
1442 char *params = *pparams;
1443 pstring directory;
1444 int ret = -1;
1445 BOOL bad_path = False;
1447 if (!CAN_WRITE(cnum))
1448 return(ERROR(ERRSRV,ERRaccess));
1450 strcpy(directory, &params[4]);
1452 DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
1454 unix_convert(directory,cnum,0,&bad_path);
1455 if (check_name(directory,cnum))
1456 ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
1458 if(ret < 0)
1460 DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
1461 if((errno == ENOENT) && bad_path)
1463 unix_ERR_class = ERRDOS;
1464 unix_ERR_code = ERRbadpath;
1466 return(UNIXERROR(ERRDOS,ERRnoaccess));
1469 /* Realloc the parameter and data sizes */
1470 params = *pparams = Realloc(*pparams,2);
1471 if(params == NULL)
1472 return(ERROR(ERRDOS,ERRnomem));
1474 SSVAL(params,0,0);
1476 send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1478 return(-1);
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)
1488 static uint16 fnf_handle = 257;
1489 char *params = *pparams;
1490 uint16 info_level = SVAL(params,4);
1492 DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
1494 switch (info_level)
1496 case 1:
1497 case 2:
1498 break;
1499 default:
1500 return(ERROR(ERRDOS,ERRunknownlevel));
1503 /* Realloc the parameter and data sizes */
1504 params = *pparams = Realloc(*pparams,6);
1505 if(params == NULL)
1506 return(ERROR(ERRDOS,ERRnomem));
1508 SSVAL(params,0,fnf_handle);
1509 SSVAL(params,2,0); /* No changes */
1510 SSVAL(params,4,0); /* No EA errors */
1512 fnf_handle++;
1514 if(fnf_handle == 0)
1515 fnf_handle = 257;
1517 send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0);
1519 return(-1);
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)
1529 char *params = *pparams;
1531 DEBUG(3,("call_trans2findnotifynext\n"));
1533 /* Realloc the parameter and data sizes */
1534 params = *pparams = Realloc(*pparams,4);
1535 if(params == NULL)
1536 return(ERROR(ERRDOS,ERRnomem));
1538 SSVAL(params,0,0); /* No changes */
1539 SSVAL(params,2,0); /* No EA errors */
1541 send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
1543 return(-1);
1546 /****************************************************************************
1547 reply to a SMBfindclose (stop trans2 directory search)
1548 ****************************************************************************/
1549 int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
1551 int cnum;
1552 int outsize = 0;
1553 int16 dptr_num=SVALS(inbuf,smb_vwv0);
1555 cnum = SVAL(inbuf,smb_tid);
1557 DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1559 dptr_close(dptr_num);
1561 outsize = set_message(outbuf,0,0,True);
1563 DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1565 return(outsize);
1568 /****************************************************************************
1569 reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search)
1570 ****************************************************************************/
1571 int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize)
1573 int cnum;
1574 int outsize = 0;
1575 int dptr_num= -1;
1577 cnum = SVAL(inbuf,smb_tid);
1578 dptr_num = SVAL(inbuf,smb_vwv0);
1580 DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1582 /* We never give out valid handles for a
1583 findnotifyfirst - so any dptr_num is ok here.
1584 Just ignore it. */
1586 outsize = set_message(outbuf,0,0,True);
1588 DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1590 return(outsize);
1594 /****************************************************************************
1595 reply to a SMBtranss2 - just ignore it!
1596 ****************************************************************************/
1597 int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize)
1599 DEBUG(4,("Ignoring transs2 of length %d\n",length));
1600 return(-1);
1603 /****************************************************************************
1604 reply to a SMBtrans2
1605 ****************************************************************************/
1606 int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
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;
1625 outsize = set_message(outbuf,0,0,True);
1627 /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
1628 is so as a sanity check */
1629 if(suwcnt != 1 )
1631 DEBUG(2,("Invalid smb_sucnt in trans2 call\n"));
1632 return(ERROR(ERRSRV,ERRerror));
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);
1641 if ((total_params && !params) || (total_data && !data))
1643 DEBUG(2,("Out of memory in reply_trans2\n"));
1644 return(ERROR(ERRDOS,ERRnomem));
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);
1652 memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
1653 memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
1655 if(num_data_sofar < total_data || num_params_sofar < total_params)
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);
1662 while( num_data_sofar < total_data || num_params_sofar < total_params)
1664 if(!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
1665 CVAL(inbuf, smb_com) != SMBtranss2)
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));
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);
1686 if (Protocol >= PROTOCOL_NT1) {
1687 uint16 flg2 = SVAL(outbuf,smb_flg2);
1688 SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1691 /* Now we must call the relevant TRANS2 function */
1692 switch(tran_call)
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));
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.
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. */