2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* UNIX SMBlib NetBIOS implementation
12 SMBlib File Access Routines
14 Copyright (C) Richard Sharpe 1996
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34 #include "rfcnb/rfcnb.h"
35 #include "smblib/smblib-priv.h"
41 /* Open a file with file_name using desired mode and search attr */
42 /* If File_Handle is null, then create and populate a file handle */
44 SMB_File
*SMB_Open(SMB_Tree_Handle Tree_Handle
,
45 SMB_File
*File_Handle
,
51 struct RFCNB_Pkt
*pkt
;
52 int pkt_len
, param_len
;
54 struct SMB_File_Def
*file_tmp
;
56 /* We allocate a file object and copy some things ... */
58 file_tmp
= File_Handle
;
60 if (File_Handle
== NULL
) {
62 if ((file_tmp
= (SMB_File
*)malloc(sizeof(SMB_File
))) == NULL
) {
65 fprintf(stderr
, "Could not allocate file handle space ...");
68 SMBlib_errno
= SMBlibE_NoSpace
;
75 strncpy(file_tmp
-> filename
, file_name
, sizeof(file_tmp
-> filename
) - 1);
76 file_tmp
-> tree
= Tree_Handle
;
77 file_tmp
-> fid
= 0xFFFF; /* Is this an invalid FID? */
79 param_len
= strlen(file_name
) + 2; /* 1 for null, 1 for ASCII marker */
81 pkt_len
= SMB_open_len
+ param_len
;
83 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(max(pkt_len
, SMB_openr_len
));
85 if (pkt
== NULL
) { /* Really should do some error handling */
87 if (File_Handle
== NULL
)
89 SMBlib_errno
= SMBlibE_NoSpace
;
94 /* Now plug in the bits we need */
96 memset(SMB_Hdr(pkt
), 0, SMB_open_len
);
97 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
98 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBopen
;
99 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, Tree_Handle
-> con
-> pid
);
100 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, Tree_Handle
-> tid
);
101 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, Tree_Handle
-> con
-> mid
);
102 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, Tree_Handle
-> con
-> uid
);
103 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 2;
105 SSVAL(SMB_Hdr(pkt
), SMB_open_mod_offset
, mode
);
106 SSVAL(SMB_Hdr(pkt
), SMB_open_atr_offset
, search
);
107 SSVAL(SMB_Hdr(pkt
), SMB_open_bcc_offset
, param_len
);
109 /* Now plug in the file name ... */
111 p
= (char *)(SMB_Hdr(pkt
) + SMB_open_buf_offset
);
113 strcpy(p
+1, file_name
);
114 p
= p
+ strlen(file_name
);
115 *(p
+1) = 0; /* plug in a null ... */
117 /* Now send the packet and get the response ... */
119 if (RFCNB_Send(Tree_Handle
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
122 fprintf(stderr
, "Error sending Open request\n");
125 if (File_Handle
== NULL
)
128 SMBlib_errno
= -SMBlibE_SendFailed
;
133 /* Now get the response ... */
136 fprintf(stderr
, "Pkt_Len for Open resp = %i\n", pkt_len
);
139 if (RFCNB_Recv(Tree_Handle
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
142 fprintf(stderr
, "Error receiving response to open request\n");
145 if (File_Handle
= NULL
)
148 SMBlib_errno
= -SMBlibE_RecvFailed
;
153 /* Now parse the response and pass back any error ... */
155 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
158 fprintf(stderr
, "SMB_Open failed with errorclass = %i, Error Code = %i\n",
159 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
160 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
163 if (File_Handle
= NULL
)
165 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
167 SMBlib_errno
= SMBlibE_Remote
;
168 return(NULL
); /* Should clean up ... */
172 file_tmp
-> fid
= SVAL(SMB_Hdr(pkt
), SMB_openr_fid_offset
);
173 file_tmp
-> lastmod
= IVAL(SMB_Hdr(pkt
), SMB_openr_tim_offset
);
174 file_tmp
-> size
= IVAL(SMB_Hdr(pkt
), SMB_openr_fsz_offset
);
175 file_tmp
-> access
= SVAL(SMB_Hdr(pkt
), SMB_openr_acc_offset
);
176 file_tmp
-> fileloc
= 0;
178 RFCNB_Free_Pkt(pkt
); /* Free up this space */
181 fprintf(stderr
, "SMB_Open succeeded, FID = %i\n", file_tmp
-> fid
);
190 /* Close the file referred to in File_Handle */
192 int SMB_Close(SMB_File
*File_Handle
)
195 struct SMB_Close_Prot_Def
*prot_pkt
;
196 struct SMB_Hdr_Def_LM12
*resp_pkt
;
197 struct RFCNB_Pkt
*pkt
;
200 if (File_Handle
== NULL
) { /* Error */
202 /*SMBLIB_errno = SMBLIBE_BadHandle; */
207 pkt_len
= SMB_clos_len
;
209 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
211 if (pkt
== NULL
) { /* Really should do some error handling */
213 SMBlib_errno
= SMBlibE_NoSpace
;
218 /* Now plug in the bits we need */
220 memset(SMB_Hdr(pkt
), 0, SMB_clos_len
);
221 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
222 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBclose
;
223 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, File_Handle
-> tree
-> con
-> pid
);
224 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, File_Handle
-> tree
-> tid
);
225 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, File_Handle
-> tree
-> con
-> mid
);
226 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, File_Handle
-> tree
-> con
-> uid
);
227 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 3;
229 SSVAL(SMB_Hdr(pkt
), SMB_clos_fid_offset
, File_Handle
-> fid
);
230 SIVAL(SMB_Hdr(pkt
), SMB_clos_tim_offset
, 0);
231 SSVAL(SMB_Hdr(pkt
), SMB_clos_bcc_offset
, 0);
233 /* Now send the packet and get the response ... */
235 if (RFCNB_Send(File_Handle
-> tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
238 fprintf(stderr
, "Error sending Open request\n");
242 SMBlib_errno
= SMBlibE_SendFailed
;
247 /* Now get the response ... */
249 if (RFCNB_Recv(File_Handle
-> tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
252 fprintf(stderr
, "Error receiving response to open request\n");
256 SMBlib_errno
= SMBlibE_RecvFailed
;
261 /* Now parse the response and pass back any error ... */
263 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
266 fprintf(stderr
, "SMB_Close failed with errorclass = %i, Error Code = %i\n",
267 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
268 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
271 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
273 SMBlib_errno
= SMBlibE_Remote
;
274 return(SMBlibE_BAD
); /* Should clean up ... */
279 fprintf(stderr
, "File %s closed successfully.\n", File_Handle
-> filename
);
282 /* We should deallocate the File_Handle now ... */
284 File_Handle
-> tree
= NULL
;
285 File_Handle
-> filename
[0] = 0;
286 File_Handle
-> fid
= 0xFFFF;
294 /* Read numbytes into data from the file pointed to by File_Handle from */
295 /* the offset in the File_Handle. */
297 int SMB_Read(SMB_File
*File_Handle
, char *data
, int numbytes
)
301 struct RFCNB_Pkt
*snd_pkt
, *recv_pkt
, *data_ptr
;
302 int snd_pkt_len
, recv_pkt_len
, this_read
, bytes_left
= numbytes
;
303 int max_read_data
, bytes_read
= 0;
305 /* We loop around, reading the data, accumulating it into the buffer */
306 /* We build an SMB packet, where the data is pointed to by a fragment*/
307 /* tagged onto the end */
309 data_ptr
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(0);
310 if (data_ptr
== NULL
) {
312 /* We should handle the error here */
314 SMBlib_errno
= SMBlibE_NoSpace
;
319 snd_pkt_len
= SMB_read_len
; /* size for the read SMB */
320 recv_pkt_len
= SMB_readr_len
+ 3; /* + 3 for the datablockID and blklen */
322 snd_pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(snd_pkt_len
);
324 if (snd_pkt
== NULL
) {
326 RFCNB_Free_Pkt(data_ptr
);
327 SMBlib_errno
= SMBlibE_NoSpace
;
332 recv_pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(recv_pkt_len
);
334 if (recv_pkt
== NULL
) {
336 RFCNB_Free_Pkt(snd_pkt
);
337 RFCNB_Free_Pkt(data_ptr
);
338 SMBlib_errno
= SMBlibE_NoSpace
;
343 /* Put the recv pkt together */
345 recv_pkt
-> next
= data_ptr
;
347 /* Now build the read request and the receive packet etc ... */
349 memset(SMB_Hdr(snd_pkt
), 0, SMB_read_len
);
350 SIVAL(SMB_Hdr(snd_pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
351 *(SMB_Hdr(snd_pkt
) + SMB_hdr_com_offset
) = SMBread
;
352 SSVAL(SMB_Hdr(snd_pkt
), SMB_hdr_pid_offset
, File_Handle
-> tree
-> con
-> pid
);
353 SSVAL(SMB_Hdr(snd_pkt
), SMB_hdr_tid_offset
, File_Handle
-> tree
-> tid
);
354 SSVAL(SMB_Hdr(snd_pkt
), SMB_hdr_mid_offset
, File_Handle
-> tree
-> con
-> mid
);
355 SSVAL(SMB_Hdr(snd_pkt
), SMB_hdr_uid_offset
, File_Handle
-> tree
-> con
-> uid
);
356 *(SMB_Hdr(snd_pkt
) + SMB_hdr_wct_offset
) = 5;
357 SSVAL(SMB_Hdr(snd_pkt
), SMB_read_fid_offset
, File_Handle
-> fid
);
359 max_read_data
= (File_Handle
-> tree
-> mbs
) - recv_pkt_len
;
361 while (bytes_left
> 0) {
363 this_read
= (bytes_left
> max_read_data
?max_read_data
: bytes_left
);
365 SSVAL(SMB_Hdr(snd_pkt
), SMB_read_cnt_offset
, this_read
);
366 SIVAL(SMB_Hdr(snd_pkt
), SMB_read_ofs_offset
, File_Handle
-> fileloc
);
367 SSVAL(SMB_Hdr(snd_pkt
), SMB_read_clf_offset
, 0x0);
368 SSVAL(SMB_Hdr(snd_pkt
), SMB_read_bcc_offset
, 0x0);
370 /* Now send the packet and wait for a response */
372 if (RFCNB_Send(File_Handle
-> tree
-> con
-> Trans_Connect
, snd_pkt
, snd_pkt_len
) < 0) {
375 fprintf(stderr
, "Error sending read request\n");
378 data_ptr
-> data
= NULL
;
380 RFCNB_Free_Pkt(recv_pkt
);
381 RFCNB_Free_Pkt(snd_pkt
);
382 SMBlib_errno
= SMBlibE_SendFailed
;
387 /* Now get the response ... first point the data portion to the right */
388 /* place in the read buffer ... what we are doing is ugly */
390 data_ptr
-> data
= (data
+ bytes_read
);
391 data_ptr
-> len
= this_read
;
393 if (RFCNB_Recv(File_Handle
-> tree
-> con
-> Trans_Connect
, recv_pkt
, recv_pkt_len
+ this_read
) < 0) {
396 fprintf(stderr
, "Error receiving response to write\n");
400 data_ptr
-> data
= NULL
;
401 RFCNB_Free_Pkt(recv_pkt
);
402 RFCNB_Free_Pkt(snd_pkt
);
403 SMBlib_errno
= SMBlibE_RecvFailed
;
408 if (CVAL(SMB_Hdr(recv_pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
411 fprintf(stderr
, "SMB_Read failed with errorclass = %i, Error Code = %i\n",
412 CVAL(SMB_Hdr(recv_pkt
), SMB_hdr_rcls_offset
),
413 SVAL(SMB_Hdr(recv_pkt
), SMB_hdr_err_offset
));
416 SMBlib_SMB_Error
= IVAL(SMB_Hdr(recv_pkt
), SMB_hdr_rcls_offset
);
417 data_ptr
-> data
= NULL
;
419 RFCNB_Free_Pkt(recv_pkt
);
420 RFCNB_Free_Pkt(snd_pkt
);
421 SMBlib_errno
= SMBlibE_Remote
;
426 /* Ok, that worked, so update some things here ... */
428 bytes_read
= bytes_read
+ SVAL(SMB_Hdr(recv_pkt
), SMB_readr_cnt_offset
);
429 bytes_left
= bytes_left
- SVAL(SMB_Hdr(recv_pkt
), SMB_readr_cnt_offset
);
433 /* Now free those packet headers that we allocated ... */
435 data_ptr
-> data
= NULL
; /* Since recv_pkt points to data_ptr */
436 data_ptr
-> len
= 0; /* it is freed too */
437 RFCNB_Free_Pkt(recv_pkt
);
438 RFCNB_Free_Pkt(snd_pkt
);
444 /* Lseek seeks just like the UNIX version does ... */
446 off_t
SMB_Lseek(SMB_File
*File_Handle
, off_t offset
, int whence
)
450 /* We should check that the file handle is kosher ... We may also blow up
451 if we get a 64 bit offset ... should avoid wrap-around ... */
456 File_Handle
-> fileloc
= offset
;
461 File_Handle
-> fileloc
= File_Handle
-> fileloc
+ offset
;
466 File_Handle
-> fileloc
= File_Handle
-> size
+ offset
;
474 return(File_Handle
-> fileloc
);
478 /* Write numbytes from data to the file pointed to by the File_Handle at */
479 /* the offset in the File_Handle. */
481 int SMB_Write(SMB_File
*File_Handle
, char *data
, int numbytes
)
485 struct RFCNB_Pkt
*pkt
, *data_ptr
;
486 int pkt_len
, i
, this_write
, max_write_data
, bytes_left
= numbytes
;
488 /* We loop around, writing the data, accumulating what was written */
489 /* We build an SMB packet, where the data is pointed to by a fragment */
490 /* tagged onto the end ... */
492 data_ptr
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(0);
493 if (data_ptr
== NULL
) {
495 SMBlib_errno
= SMBlibE_NoSpace
;
500 pkt_len
= SMB_write_len
+ 3; /* + 3 for the datablockID and blklen */
502 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
506 RFCNB_Free_Pkt(data_ptr
);
507 SMBlib_errno
= SMBlibE_NoSpace
;
512 /* Now init the things that will be the same across the possibly multiple
513 packets to write this data. */
515 memset(SMB_Hdr(pkt
), 0, SMB_write_len
);
516 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
517 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBwrite
;
518 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, File_Handle
-> tree
-> con
-> pid
);
519 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, File_Handle
-> tree
-> tid
);
520 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, File_Handle
-> tree
-> con
-> mid
);
521 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, File_Handle
-> tree
-> con
-> uid
);
522 SSVAL(SMB_Hdr(pkt
), SMB_write_fid_offset
, File_Handle
-> fid
);
524 /* We will program this as send/response for the moment, but if we could
525 only send the second block before getting the first, we could speed
526 things up a bit ... */
528 max_write_data
= (File_Handle
-> tree
-> mbs
) - pkt_len
;
530 /* the 3 is for the data block id and length that preceeds the data */
532 while (bytes_left
> 0) {
534 /* bytes to write? */
536 this_write
= (bytes_left
> max_write_data
?max_write_data
:bytes_left
);
538 data_ptr
-> next
= NULL
;
539 data_ptr
-> len
= this_write
;
540 data_ptr
-> data
= data
+ tot_written
;
542 pkt
-> next
= data_ptr
; /* link the data on the end */
544 SSVAL(SMB_Hdr(pkt
), SMB_hdr_flg_offset
, 0);
545 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 5;
546 SSVAL(SMB_Hdr(pkt
), SMB_write_fid_offset
, File_Handle
-> fid
);
547 SSVAL(SMB_Hdr(pkt
), SMB_write_cnt_offset
, this_write
);
548 SIVAL(SMB_Hdr(pkt
), SMB_write_ofs_offset
, File_Handle
-> fileloc
);
549 SSVAL(SMB_Hdr(pkt
), SMB_write_clf_offset
, 0);
550 SSVAL(SMB_Hdr(pkt
), SMB_write_bcc_offset
, (this_write
+ 3));
552 *(SMB_Hdr(pkt
) + SMB_write_buf_offset
) = SMBdatablockID
;
553 SSVAL(SMB_Hdr(pkt
), SMB_write_buf_offset
+ 1, this_write
);
555 /* Now send the packet and wait for a response */
557 if (RFCNB_Send(File_Handle
-> tree
-> con
-> Trans_Connect
, pkt
, pkt_len
+ this_write
) < 0) {
560 fprintf(stderr
, "Error sending write request\n");
563 data_ptr
-> next
= NULL
;
566 SMBlib_errno
= -SMBlibE_SendFailed
;
571 /* Now get the response ... */
573 if (RFCNB_Recv(File_Handle
-> tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
576 fprintf(stderr
, "Error receiving response to write\n");
579 data_ptr
-> next
= NULL
;
582 SMBlib_errno
= -SMBlibE_RecvFailed
;
587 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
590 fprintf(stderr
, "SMB_Write failed with errorclass = %i, Error Code = %i\n",
591 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
592 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
595 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
596 data_ptr
-> data
= NULL
;
599 SMBlib_errno
= SMBlibE_Remote
;
604 /* Ok, that worked, so update some things here ... */
606 tot_written
= tot_written
+ this_write
;
607 bytes_left
= bytes_left
- this_write
;
609 /* Assume that it is ok to update this now, but what about only part */
610 /* of the write succeeding? */
612 File_Handle
-> fileloc
= File_Handle
-> fileloc
+ this_write
;
615 fprintf(stderr
, "--This_write = %i, bytes_left = %i\n",
616 this_write
, bytes_left
);
621 /* Let's get rid of those packet headers we are using ... */
623 data_ptr
-> data
= NULL
;
632 /* Create file on the server with name file_name and attributes search */
634 SMB_File
*SMB_Create(SMB_Tree_Handle Tree_Handle
,
635 SMB_File
*File_Handle
,
640 struct RFCNB_Pkt
*pkt
;
641 int pkt_len
, param_len
;
643 struct SMB_File_Def
*file_tmp
;
645 /* We allocate a file object and copy some things ... */
647 file_tmp
= File_Handle
;
649 if (File_Handle
== NULL
) {
651 if ((file_tmp
= (SMB_File
*)malloc(sizeof(SMB_File
))) == NULL
) {
654 fprintf(stderr
, "Could not allocate file handle space ...");
657 SMBlib_errno
= SMBlibE_NoSpace
;
664 strncpy(file_tmp
-> filename
, file_name
, sizeof(file_tmp
-> filename
));
665 file_tmp
-> tree
= Tree_Handle
;
666 file_tmp
-> fid
= 0xFFFF; /* Is this an invalid FID? */
668 param_len
= strlen(file_name
) + 2; /* 1 for null, 1 for ASCII marker */
670 pkt_len
= SMB_creat_len
+ param_len
;
672 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
674 if (pkt
== NULL
) { /* Really should do some error handling */
676 if (File_Handle
== NULL
)
678 SMBlib_errno
= SMBlibE_NoSpace
;
683 /* Now plug in the bits we need */
685 memset(SMB_Hdr(pkt
), 0, SMB_creat_len
);
686 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
687 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBcreate
;
688 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, Tree_Handle
-> con
-> pid
);
689 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, Tree_Handle
-> tid
);
690 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, Tree_Handle
-> con
-> mid
);
691 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, Tree_Handle
-> con
-> uid
);
692 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 3;
694 SSVAL(SMB_Hdr(pkt
), SMB_creat_atr_offset
, search
);
695 SSVAL(SMB_Hdr(pkt
), SMB_creat_tim_offset
, 0);
696 SSVAL(SMB_Hdr(pkt
), SMB_creat_dat_offset
, 0);
697 SSVAL(SMB_Hdr(pkt
), SMB_creat_bcc_offset
, param_len
);
699 /* Now plug in the file name ... */
701 p
= (char *)(SMB_Hdr(pkt
) + SMB_creat_buf_offset
);
703 strcpy(p
+1, file_name
);
704 p
= p
+ strlen(file_name
);
705 *(p
+1) = 0; /* plug in a null ... */
707 /* Now send the packet and get the response ... */
709 if (RFCNB_Send(Tree_Handle
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
712 fprintf(stderr
, "Error sending Open request\n");
715 if (File_Handle
== NULL
)
718 SMBlib_errno
= -SMBlibE_SendFailed
;
723 /* Now get the response ... */
726 fprintf(stderr
, "Pkt_Len for Create resp = %i\n", pkt_len
);
729 if (RFCNB_Recv(Tree_Handle
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
732 fprintf(stderr
, "Error receiving response to create request\n");
735 if (File_Handle
== NULL
)
738 SMBlib_errno
= -SMBlibE_RecvFailed
;
743 /* Now parse the response and pass back any error ... */
745 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
748 fprintf(stderr
, "SMB_Create failed with errorclass = %i, Error Code = %i\n",
749 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
750 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
753 if (File_Handle
== NULL
)
755 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
757 SMBlib_errno
= SMBlibE_Remote
;
758 return(NULL
); /* Should clean up ... */
762 file_tmp
-> fid
= SVAL(SMB_Hdr(pkt
), SMB_creatr_fid_offset
);
763 file_tmp
-> lastmod
= 0;
764 file_tmp
-> size
= 0;
765 file_tmp
-> access
= SMB_AMODE_OPENRW
;
766 file_tmp
-> fileloc
= 0;
768 RFCNB_Free_Pkt(pkt
); /* Free up this space */
771 fprintf(stderr
, "SMB_Create succeeded, FID = %i\n", file_tmp
-> fid
);
778 /* Delete the file passed in as file_name. */
780 int SMB_Delete(SMB_Tree_Handle tree
, char *file_name
, WORD search
)
783 struct RFCNB_Pkt
*pkt
;
784 int pkt_len
, param_len
;
787 param_len
= strlen(file_name
) + 2;
788 pkt_len
= SMB_delet_len
+ param_len
;
790 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
792 if (pkt
== NULL
) { /* Really should do some error handling */
794 SMBlib_errno
= SMBlibE_NoSpace
;
799 /* Now plug in the bits we need */
801 memset(SMB_Hdr(pkt
), 0, SMB_delet_len
);
802 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
803 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBunlink
;
804 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, tree
-> con
-> pid
);
805 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, tree
-> tid
);
806 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, tree
-> con
-> mid
);
807 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, tree
-> con
-> uid
);
808 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 1;
810 SIVAL(SMB_Hdr(pkt
), SMB_delet_sat_offset
, search
);
811 SSVAL(SMB_Hdr(pkt
), SMB_delet_bcc_offset
, param_len
);
813 /* Now plug in the file name ... */
815 p
= (char *)(SMB_Hdr(pkt
) + SMB_delet_buf_offset
);
817 strcpy(p
+1, file_name
);
818 p
= p
+ strlen(file_name
);
819 *(p
+1) = 0; /* plug in a null ... */
821 /* Now send the packet and get the response ... */
823 if (RFCNB_Send(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
826 fprintf(stderr
, "Error sending Delete request\n");
830 SMBlib_errno
= -SMBlibE_SendFailed
;
835 /* Now get the response ... */
837 if (RFCNB_Recv(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
840 fprintf(stderr
, "Error receiving response to delete request\n");
844 SMBlib_errno
= -SMBlibE_RecvFailed
;
849 /* Now parse the response and pass back any error ... */
851 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
854 fprintf(stderr
, "SMB_Delete failed with errorclass = %i, Error Code = %i\n",
855 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
856 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
859 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
861 SMBlib_errno
= SMBlibE_Remote
;
862 return(SMBlibE_BAD
); /* Should clean up ... */
867 fprintf(stderr
, "File %s deleted successfully.\n", file_name
);
875 /* Create the directory passed in as dir_name */
877 int SMB_Create_Dir(SMB_Tree_Handle tree
, char *dir_name
)
880 struct RFCNB_Pkt
*pkt
;
881 int pkt_len
, param_len
;
884 param_len
= strlen(dir_name
) + 2; /* + null and + asciiID */
885 pkt_len
= SMB_creatdir_len
+ param_len
;
887 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
889 if (pkt
== NULL
) { /* Really should do some error handling */
891 SMBlib_errno
= SMBlibE_NoSpace
;
896 /* Now plug in the bits we need */
898 memset(SMB_Hdr(pkt
), 0, SMB_creatdir_len
);
899 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
900 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBmkdir
;
901 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, tree
-> con
-> pid
);
902 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, tree
-> tid
);
903 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, tree
-> con
-> mid
);
904 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, tree
-> con
-> uid
);
905 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 0;
907 SSVAL(SMB_Hdr(pkt
), SMB_creatdir_bcc_offset
, param_len
);
909 /* Now plug in the file name ... */
911 p
= (char *)(SMB_Hdr(pkt
) + SMB_creatdir_buf_offset
);
913 strcpy(p
+1, dir_name
);
914 p
= p
+ strlen(dir_name
);
915 *(p
+1) = 0; /* plug in a null ... */
917 /* Now send the packet and get the response ... */
919 if (RFCNB_Send(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
922 fprintf(stderr
, "Error sending Create Dir request\n");
926 SMBlib_errno
= -SMBlibE_SendFailed
;
931 /* Now get the response ... */
933 if (RFCNB_Recv(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
936 fprintf(stderr
, "Error receiving response to Create Dir request\n");
940 SMBlib_errno
= -SMBlibE_RecvFailed
;
945 /* Now parse the response and pass back any error ... */
947 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
950 fprintf(stderr
, "SMB_Create_Dir failed with errorclass = %i, Error Code = %i\n",
951 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
952 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
955 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
957 SMBlib_errno
= SMBlibE_Remote
;
958 return(SMBlibE_BAD
); /* Should clean up ... */
963 fprintf(stderr
, "Directory %s created successfully.\n", dir_name
);
971 /* Delete the directory passed as dir_name, as long as it is empty ... */
973 int SMB_Delete_Dir(SMB_Tree_Handle tree
, char *dir_name
)
976 struct RFCNB_Pkt
*pkt
;
977 int pkt_len
, param_len
;
980 param_len
= strlen(dir_name
) + 2; /* + null and + asciiID */
981 pkt_len
= SMB_deletdir_len
+ param_len
;
983 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
985 if (pkt
== NULL
) { /* Really should do some error handling */
987 SMBlib_errno
= SMBlibE_NoSpace
;
992 /* Now plug in the bits we need */
994 memset(SMB_Hdr(pkt
), 0, SMB_deletdir_len
);
995 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
996 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBrmdir
;
997 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, tree
-> con
-> pid
);
998 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, tree
-> tid
);
999 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, tree
-> con
-> mid
);
1000 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, tree
-> con
-> uid
);
1001 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 0;
1003 SSVAL(SMB_Hdr(pkt
), SMB_deletdir_bcc_offset
, param_len
);
1005 /* Now plug in the file name ... */
1007 p
= (char *)(SMB_Hdr(pkt
) + SMB_deletdir_buf_offset
);
1009 strcpy(p
+1, dir_name
);
1010 p
= p
+ strlen(dir_name
);
1011 *(p
+1) = 0; /* plug in a null ... */
1013 /* Now send the packet and get the response ... */
1015 if (RFCNB_Send(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
1018 fprintf(stderr
, "Error sending Delete Dir request\n");
1021 RFCNB_Free_Pkt(pkt
);
1022 SMBlib_errno
= -SMBlibE_SendFailed
;
1023 return(SMBlibE_BAD
);
1027 /* Now get the response ... */
1029 if (RFCNB_Recv(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
1032 fprintf(stderr
, "Error receiving response to Delete Dir request\n");
1035 RFCNB_Free_Pkt(pkt
);
1036 SMBlib_errno
= -SMBlibE_RecvFailed
;
1037 return(SMBlibE_BAD
);
1041 /* Now parse the response and pass back any error ... */
1043 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
1046 fprintf(stderr
, "SMB_Delete_Dir failed with errorclass = %i, Error Code = %i\n",
1047 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
1048 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
1051 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
1052 RFCNB_Free_Pkt(pkt
);
1053 SMBlib_errno
= SMBlibE_Remote
;
1054 return(SMBlibE_BAD
); /* Should clean up ... */
1059 fprintf(stderr
, "Directory %s deleted successfully.\n", dir_name
);
1062 RFCNB_Free_Pkt(pkt
);
1067 /* Check for the existence of the directory in dir_name */
1069 int SMB_Check_Dir(SMB_Tree_Handle tree
, char *dir_name
)
1072 struct RFCNB_Pkt
*pkt
;
1073 int pkt_len
, param_len
;
1076 param_len
= strlen(dir_name
) + 2; /* + null and + asciiID */
1077 pkt_len
= SMB_checkdir_len
+ param_len
;
1079 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
1081 if (pkt
== NULL
) { /* Really should do some error handling */
1083 SMBlib_errno
= SMBlibE_NoSpace
;
1084 return(SMBlibE_BAD
);
1088 /* Now plug in the bits we need */
1090 memset(SMB_Hdr(pkt
), 0, SMB_checkdir_len
);
1091 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
1092 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBchkpth
;
1093 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, tree
-> con
-> pid
);
1094 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, tree
-> tid
);
1095 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, tree
-> con
-> mid
);
1096 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, tree
-> con
-> uid
);
1097 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 0;
1099 SSVAL(SMB_Hdr(pkt
), SMB_checkdir_bcc_offset
, param_len
);
1101 /* Now plug in the file name ... */
1103 p
= (char *)(SMB_Hdr(pkt
) + SMB_checkdir_buf_offset
);
1105 strcpy(p
+1, dir_name
);
1106 p
= p
+ strlen(dir_name
);
1107 *(p
+1) = 0; /* plug in a null ... */
1109 /* Now send the packet and get the response ... */
1111 if (RFCNB_Send(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
1114 fprintf(stderr
, "Error sending Check Dir Path request\n");
1117 RFCNB_Free_Pkt(pkt
);
1118 SMBlib_errno
= -SMBlibE_SendFailed
;
1119 return(SMBlibE_BAD
);
1123 /* Now get the response ... */
1125 if (RFCNB_Recv(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
1128 fprintf(stderr
, "Error receiving response to Check Dir request\n");
1131 RFCNB_Free_Pkt(pkt
);
1132 SMBlib_errno
= -SMBlibE_RecvFailed
;
1133 return(SMBlibE_BAD
);
1137 /* Now parse the response and pass back any error ... */
1139 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
1142 fprintf(stderr
, "SMB_Check_Dir failed with errorclass = %i, Error Code = %i\n",
1143 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
1144 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
1147 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
1148 RFCNB_Free_Pkt(pkt
);
1149 SMBlib_errno
= SMBlibE_Remote
;
1150 return(SMBlibE_BAD
); /* Should clean up ... */
1155 fprintf(stderr
, "Directory %s checked successfully.\n", dir_name
);
1158 RFCNB_Free_Pkt(pkt
);
1163 /* Search directory for the files listed ... Relative to the TID in the */
1164 /* Con Handle. Return number of Dir Ents returned as the result. */
1166 int SMB_Search(SMB_Tree_Handle tree
,
1169 SMB_CP_dirent
*dirents
,
1175 struct RFCNB_Pkt
*pkt
, *recv_pkt
;
1176 int pkt_len
, param_len
, recv_param_len
, recv_pkt_len
, ret_count
, i
;
1179 param_len
= strlen(dir_name
) + 2 + resumekey_len
+ 3; /* You have to know */
1180 pkt_len
= SMB_search_len
+ param_len
;
1182 recv_param_len
= direntc
* SMB_searchr_dirent_len
+ 3;
1183 recv_pkt_len
= SMB_searchr_len
+ recv_param_len
;
1185 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
1187 if (pkt
== NULL
) { /* Really should do some error handling */
1189 SMBlib_errno
= SMBlibE_NoSpace
;
1190 return(SMBlibE_BAD
);
1194 recv_pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(recv_pkt_len
);
1196 if (recv_pkt
== NULL
) { /* Really should do some error handling */
1198 RFCNB_Free_Pkt(pkt
);
1199 SMBlib_errno
= SMBlibE_NoSpace
;
1200 return(SMBlibE_BAD
);
1204 /* Now plug in the bits we need */
1206 memset(SMB_Hdr(pkt
), 0, SMB_search_len
);
1207 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
1208 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBsearch
;
1209 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, tree
-> con
-> pid
);
1210 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, tree
-> tid
);
1211 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, tree
-> con
-> mid
);
1212 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, tree
-> con
-> uid
);
1214 /* Tell server we known about non-dos names and extended attibutes */
1216 SSVAL(SMB_Hdr(pkt
), SMB_hdr_flg2_offset
,
1217 (SMB_FLG2_NON_DOS
| SMB_FLG2_EXT_ATR
));
1219 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 2;
1221 SSVAL(SMB_Hdr(pkt
), SMB_search_mdc_offset
, direntc
); /* How many we want */
1222 SSVAL(SMB_Hdr(pkt
), SMB_search_atr_offset
, search
);
1223 SSVAL(SMB_Hdr(pkt
), SMB_search_bcc_offset
, param_len
);
1225 /* Now plug in the file name ... */
1227 p
= (char *)(SMB_Hdr(pkt
) + SMB_search_buf_offset
);
1229 strcpy(p
+1, dir_name
);
1230 p
= p
+ strlen(dir_name
) + 2; /* Skip the null */
1232 *p
= SMBvariableblockID
;
1235 /* And now the resume key */
1237 SSVAL(p
, 0, resumekey_len
);
1241 bcopy(resumekey
, p
, resumekey_len
);
1243 /* Now send the packet and get the response ... */
1245 if (RFCNB_Send(tree
-> con
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
1248 fprintf(stderr
, "Error sending search request\n");
1251 RFCNB_Free_Pkt(pkt
);
1252 RFCNB_Free_Pkt(recv_pkt
);
1253 SMBlib_errno
= -SMBlibE_SendFailed
;
1254 return(SMBlibE_BAD
);
1258 /* Now get the response ... */
1260 if (RFCNB_Recv(tree
-> con
-> Trans_Connect
, recv_pkt
, recv_pkt_len
) < 0) {
1263 fprintf(stderr
, "Error receiving response to Check Dir request\n");
1266 RFCNB_Free_Pkt(pkt
);
1267 RFCNB_Free_Pkt(recv_pkt
);
1268 SMBlib_errno
= -SMBlibE_RecvFailed
;
1269 return(SMBlibE_BAD
);
1273 /* Now parse the response and pass back any error ... */
1275 if (CVAL(SMB_Hdr(recv_pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
1278 fprintf(stderr
, "SMB_Check_Dir failed with errorclass = %i, Error Code = %i\n",
1279 CVAL(SMB_Hdr(recv_pkt
), SMB_hdr_rcls_offset
),
1280 SVAL(SMB_Hdr(recv_pkt
), SMB_hdr_err_offset
));
1283 SMBlib_SMB_Error
= IVAL(SMB_Hdr(recv_pkt
), SMB_hdr_rcls_offset
);
1284 RFCNB_Free_Pkt(pkt
);
1285 RFCNB_Free_Pkt(recv_pkt
);
1286 SMBlib_errno
= SMBlibE_Remote
;
1287 return(SMBlibE_BAD
); /* Should clean up ... */
1291 /* Now copy the results into the user's structure */
1293 ret_count
= SVAL(SMB_Hdr(recv_pkt
), SMB_searchr_dec_offset
);
1295 p
= SMB_Hdr(recv_pkt
) + SMB_searchr_buf_offset
+ 3;
1297 /* Hmmm, should check that we have the right number of bytes ... */
1299 for (i
= 0; i
< ret_count
; i
++) {
1301 bcopy(p
, dirents
[i
].resume_key
, 21);
1305 dirents
[i
].file_attributes
= (unsigned char)*p
;
1309 dirents
[i
].date_time
= IVAL(p
, 0); /* Should this be IVAL? */
1313 dirents
[i
].size
= IVAL(p
, 0);
1317 bcopy(p
, dirents
[i
].filename
, 13); /* Copy in file name */