diff options
Diffstat (limited to 'daemon/smblib/file.c')
-rw-r--r-- | daemon/smblib/file.c | 1306 |
1 files changed, 1306 insertions, 0 deletions
diff --git a/daemon/smblib/file.c b/daemon/smblib/file.c new file mode 100644 index 0000000..6a62da5 --- /dev/null +++ b/daemon/smblib/file.c @@ -0,0 +1,1306 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMBlib File Access Routines + + Copyright (C) Richard Sharpe 1996 + +*/ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "smblib-priv.h" + +#include "../rfcnb/rfcnb.h" + +/* Open a file with file_name using desired mode and search attr */ +/* If File_Handle is null, then create and populate a file handle */ + +SMB_File *SMB_Open(SMB_Tree_Handle Tree_Handle, + SMB_File *File_Handle, + char *file_name, + WORD mode, + WORD search) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; char *p; + struct SMB_File_Def *file_tmp; + + /* We allocate a file object and copy some things ... */ + + file_tmp = File_Handle; + + if (File_Handle == NULL) { + + if ((file_tmp = (SMB_File *)malloc(sizeof(SMB_File))) == NULL){ + +#ifdef DEBUG + fprintf(stderr, "Could not allocate file handle space ..."); +#endif + + SMBlib_errno = SMBlibE_NoSpace; + return(NULL); + + } + + } + + strncpy(file_tmp -> filename, file_name, sizeof(file_tmp -> filename) - 1); + file_tmp -> tree = Tree_Handle; + file_tmp -> fid = 0xFFFF; /* Is this an invalid FID? */ + + param_len = strlen(file_name) + 2; /* 1 for null, 1 for ASCII marker */ + + pkt_len = SMB_open_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(max(pkt_len, SMB_openr_len)); + + if (pkt == NULL) { /* Really should do some error handling */ + + if (File_Handle == NULL) + free(file_tmp); + SMBlib_errno = SMBlibE_NoSpace; + return(NULL); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_open_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBopen; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 2; + + SSVAL(SMB_Hdr(pkt), SMB_open_mod_offset, mode); + SSVAL(SMB_Hdr(pkt), SMB_open_atr_offset, search); + SSVAL(SMB_Hdr(pkt), SMB_open_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_open_buf_offset); + *p = SMBasciiID; + strcpy(p+1, file_name); + p = p + strlen(file_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Open request\n"); +#endif + + if (File_Handle == NULL) + free(file_tmp); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(NULL); + + } + + /* Now get the response ... */ + +#ifdef DEBUG + fprintf(stderr, "Pkt_Len for Open resp = %i\n", pkt_len); +#endif + + if (RFCNB_Recv(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to open request\n"); +#endif + + if (File_Handle = NULL) + free(file_tmp); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(NULL); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Open failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + if (File_Handle = NULL) + free(file_tmp); + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(NULL); /* Should clean up ... */ + + } + + file_tmp -> fid = SVAL(SMB_Hdr(pkt), SMB_openr_fid_offset); + file_tmp -> lastmod = IVAL(SMB_Hdr(pkt), SMB_openr_tim_offset); + file_tmp -> size = IVAL(SMB_Hdr(pkt), SMB_openr_fsz_offset); + file_tmp -> access = SVAL(SMB_Hdr(pkt), SMB_openr_acc_offset); + file_tmp -> fileloc = 0; + + RFCNB_Free_Pkt(pkt); /* Free up this space */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Open succeeded, FID = %i\n", file_tmp -> fid); +#endif + + RFCNB_Free_Pkt(pkt); + + return(file_tmp); + +} + +/* Close the file referred to in File_Handle */ + +int SMB_Close(SMB_File *File_Handle) + +{ struct SMB_Close_Prot_Def *prot_pkt; + struct SMB_Hdr_Def_LM12 *resp_pkt; + struct RFCNB_Pkt *pkt; + int pkt_len; + + if (File_Handle == NULL) { /* Error */ + + /*SMBLIB_errno = SMBLIBE_BadHandle; */ + return(-1); + + } + + pkt_len = SMB_clos_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_clos_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBclose; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, File_Handle -> tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, File_Handle -> tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, File_Handle -> tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, File_Handle -> tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 3; + + SSVAL(SMB_Hdr(pkt), SMB_clos_fid_offset, File_Handle -> fid); + SIVAL(SMB_Hdr(pkt), SMB_clos_tim_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_clos_bcc_offset, 0); + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(File_Handle -> tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Open request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(File_Handle -> tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to open request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Close failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "File %s closed successfully.\n", File_Handle -> filename); +#endif /* DEBUG */ + + /* We should deallocate the File_Handle now ... */ + + File_Handle -> tree = NULL; + File_Handle -> filename[0] = 0; + File_Handle -> fid = 0xFFFF; + + RFCNB_Free_Pkt(pkt); + free(File_Handle); + + return(0); +} + +/* Read numbytes into data from the file pointed to by File_Handle from */ +/* the offset in the File_Handle. */ + +int SMB_Read(SMB_File *File_Handle, char *data, int numbytes) + +{ int tot_read; + struct RFCNB_Pkt *snd_pkt, *recv_pkt, *data_ptr; + int snd_pkt_len, recv_pkt_len, this_read, bytes_left = numbytes; + int max_read_data, bytes_read = 0; + + /* We loop around, reading the data, accumulating it into the buffer */ + /* We build an SMB packet, where the data is pointed to by a fragment*/ + /* tagged onto the end */ + + data_ptr = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(0); + if (data_ptr == NULL) { + + /* We should handle the error here */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + snd_pkt_len = SMB_read_len; /* size for the read SMB */ + recv_pkt_len = SMB_readr_len + 3; /* + 3 for the datablockID and blklen */ + + snd_pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(snd_pkt_len); + + if (snd_pkt == NULL) { + + RFCNB_Free_Pkt(data_ptr); + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + recv_pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(recv_pkt_len); + + if (recv_pkt == NULL) { + + RFCNB_Free_Pkt(snd_pkt); + RFCNB_Free_Pkt(data_ptr); + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Put the recv pkt together */ + + recv_pkt -> next = data_ptr; + + /* Now build the read request and the receive packet etc ... */ + + bzero(SMB_Hdr(snd_pkt), SMB_read_len); + SIVAL(SMB_Hdr(snd_pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(snd_pkt) + SMB_hdr_com_offset) = SMBread; + SSVAL(SMB_Hdr(snd_pkt), SMB_hdr_pid_offset, File_Handle -> tree -> con -> pid); + SSVAL(SMB_Hdr(snd_pkt), SMB_hdr_tid_offset, File_Handle -> tree -> tid); + SSVAL(SMB_Hdr(snd_pkt), SMB_hdr_mid_offset, File_Handle -> tree -> con -> mid); + SSVAL(SMB_Hdr(snd_pkt), SMB_hdr_uid_offset, File_Handle -> tree -> con -> uid); + *(SMB_Hdr(snd_pkt) + SMB_hdr_wct_offset) = 5; + SSVAL(SMB_Hdr(snd_pkt), SMB_read_fid_offset, File_Handle -> fid); + + max_read_data = (File_Handle -> tree -> mbs) - recv_pkt_len; + + while (bytes_left > 0) { + + this_read = (bytes_left > max_read_data?max_read_data: bytes_left); + + SSVAL(SMB_Hdr(snd_pkt), SMB_read_cnt_offset, this_read); + SIVAL(SMB_Hdr(snd_pkt), SMB_read_ofs_offset, File_Handle -> fileloc); + SSVAL(SMB_Hdr(snd_pkt), SMB_read_clf_offset, 0x0); + SSVAL(SMB_Hdr(snd_pkt), SMB_read_bcc_offset, 0x0); + + /* Now send the packet and wait for a response */ + + if (RFCNB_Send(File_Handle -> tree -> con -> Trans_Connect, snd_pkt, snd_pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending read request\n"); +#endif + + data_ptr -> data = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(recv_pkt); + RFCNB_Free_Pkt(snd_pkt); + SMBlib_errno = SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... first point the data portion to the right */ + /* place in the read buffer ... what we are doing is ugly */ + + data_ptr -> data = (data + bytes_read); + data_ptr -> len = this_read; + + if (RFCNB_Recv(File_Handle -> tree -> con -> Trans_Connect, recv_pkt, recv_pkt_len + this_read) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to write\n"); +#endif + + data_ptr -> len = 0; + data_ptr -> data = NULL; + RFCNB_Free_Pkt(recv_pkt); + RFCNB_Free_Pkt(snd_pkt); + SMBlib_errno = SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + if (CVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Read failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(recv_pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset); + data_ptr -> data = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(recv_pkt); + RFCNB_Free_Pkt(snd_pkt); + SMBlib_errno = SMBlibE_Remote; + return(-1); + + } + + /* Ok, that worked, so update some things here ... */ + + bytes_read = bytes_read + SVAL(SMB_Hdr(recv_pkt), SMB_readr_cnt_offset); + bytes_left = bytes_left - SVAL(SMB_Hdr(recv_pkt), SMB_readr_cnt_offset); + + } + + /* Now free those packet headers that we allocated ... */ + + data_ptr -> data = NULL; /* Since recv_pkt points to data_ptr */ + data_ptr -> len = 0; /* it is freed too */ + RFCNB_Free_Pkt(recv_pkt); + RFCNB_Free_Pkt(snd_pkt); + + return(bytes_read); + +} + +/* Lseek seeks just like the UNIX version does ... */ + +off_t SMB_Lseek(SMB_File *File_Handle, off_t offset, int whence) + +{ + + /* We should check that the file handle is kosher ... We may also blow up + if we get a 64 bit offset ... should avoid wrap-around ... */ + + switch (whence) { + case SEEK_SET: + + File_Handle -> fileloc = offset; + break; + + case SEEK_CUR: + + File_Handle -> fileloc = File_Handle -> fileloc + offset; + break; + + case SEEK_END: + + File_Handle -> fileloc = File_Handle -> size + offset; + break; + + default: + return(-1); + + } + + return(File_Handle -> fileloc); + +} + + +/* Write numbytes from data to the file pointed to by the File_Handle at */ +/* the offset in the File_Handle. */ + +int SMB_Write(SMB_File *File_Handle, char *data, int numbytes) + +{ int tot_written = 0; + struct RFCNB_Pkt *pkt, *data_ptr; + int pkt_len, i, this_write, max_write_data, bytes_left = numbytes; + + /* We loop around, writing the data, accumulating what was written */ + /* We build an SMB packet, where the data is pointed to by a fragment */ + /* tagged onto the end ... */ + + data_ptr = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(0); + if (data_ptr == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + pkt_len = SMB_write_len + 3; /* + 3 for the datablockID and blklen */ + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + RFCNB_Free_Pkt(data_ptr); + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now init the things that will be the same across the possibly multiple + packets to write this data. */ + + bzero(SMB_Hdr(pkt), SMB_write_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBwrite; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, File_Handle -> tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, File_Handle -> tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, File_Handle -> tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, File_Handle -> tree -> con -> uid); + SSVAL(SMB_Hdr(pkt), SMB_write_fid_offset, File_Handle -> fid); + + /* We will program this as send/response for the moment, but if we could + only send the second block before getting the first, we could speed + things up a bit ... */ + + max_write_data = (File_Handle -> tree -> mbs) - pkt_len; + + /* the 3 is for the data block id and length that preceeds the data */ + + while (bytes_left > 0) { + + /* bytes to write? */ + + this_write = (bytes_left > max_write_data?max_write_data:bytes_left); + + data_ptr -> next = NULL; + data_ptr -> len = this_write; + data_ptr -> data = data + tot_written; + + pkt -> next = data_ptr; /* link the data on the end */ + + SSVAL(SMB_Hdr(pkt), SMB_hdr_flg_offset, 0); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 5; + SSVAL(SMB_Hdr(pkt), SMB_write_fid_offset, File_Handle -> fid); + SSVAL(SMB_Hdr(pkt), SMB_write_cnt_offset, this_write); + SIVAL(SMB_Hdr(pkt), SMB_write_ofs_offset, File_Handle -> fileloc); + SSVAL(SMB_Hdr(pkt), SMB_write_clf_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_write_bcc_offset, (this_write + 3)); + + *(SMB_Hdr(pkt) + SMB_write_buf_offset) = SMBdatablockID; + SSVAL(SMB_Hdr(pkt), SMB_write_buf_offset + 1, this_write); + + /* Now send the packet and wait for a response */ + + if (RFCNB_Send(File_Handle -> tree -> con -> Trans_Connect, pkt, pkt_len + this_write) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending write request\n"); +#endif + + data_ptr -> next = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(-1); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(File_Handle -> tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to write\n"); +#endif + + data_ptr -> next = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(-1); + + } + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Write failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + data_ptr -> data = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); + + } + + /* Ok, that worked, so update some things here ... */ + + tot_written = tot_written + this_write; + bytes_left = bytes_left - this_write; + + /* Assume that it is ok to update this now, but what about only part */ + /* of the write succeeding? */ + + File_Handle -> fileloc = File_Handle -> fileloc + this_write; + +#ifdef DEBUG + fprintf(stderr, "--This_write = %i, bytes_left = %i\n", + this_write, bytes_left); +#endif + + } + + /* Let's get rid of those packet headers we are using ... */ + + data_ptr -> data = NULL; + pkt -> next = NULL; + + RFCNB_Free_Pkt(pkt); + + return(tot_written); + +} + +/* Create file on the server with name file_name and attributes search */ + +SMB_File *SMB_Create(SMB_Tree_Handle Tree_Handle, + SMB_File *File_Handle, + char *file_name, + WORD search) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; char *p; + struct SMB_File_Def *file_tmp; + + /* We allocate a file object and copy some things ... */ + + file_tmp = File_Handle; + + if (File_Handle == NULL) { + + if ((file_tmp = (SMB_File *)malloc(sizeof(SMB_File))) == NULL){ + +#ifdef DEBUG + fprintf(stderr, "Could not allocate file handle space ..."); +#endif + + SMBlib_errno = SMBlibE_NoSpace; + return(NULL); + + } + + } + + strncpy(file_tmp -> filename, file_name, sizeof(file_tmp -> filename)); + file_tmp -> tree = Tree_Handle; + file_tmp -> fid = 0xFFFF; /* Is this an invalid FID? */ + + param_len = strlen(file_name) + 2; /* 1 for null, 1 for ASCII marker */ + + pkt_len = SMB_creat_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + if (File_Handle == NULL) + free(file_tmp); + SMBlib_errno = SMBlibE_NoSpace; + return(NULL); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_creat_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBcreate; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 3; + + SSVAL(SMB_Hdr(pkt), SMB_creat_atr_offset, search); + SSVAL(SMB_Hdr(pkt), SMB_creat_tim_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_creat_dat_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_creat_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_creat_buf_offset); + *p = SMBasciiID; + strcpy(p+1, file_name); + p = p + strlen(file_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Open request\n"); +#endif + + if (File_Handle == NULL) + free(file_tmp); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(NULL); + + } + + /* Now get the response ... */ + +#ifdef DEBUG + fprintf(stderr, "Pkt_Len for Create resp = %i\n", pkt_len); +#endif + + if (RFCNB_Recv(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to create request\n"); +#endif + + if (File_Handle == NULL) + free(file_tmp); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(NULL); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Create failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + if (File_Handle == NULL) + free(file_tmp); + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(NULL); /* Should clean up ... */ + + } + + file_tmp -> fid = SVAL(SMB_Hdr(pkt), SMB_creatr_fid_offset); + file_tmp -> lastmod = 0; + file_tmp -> size = 0; + file_tmp -> access = SMB_AMODE_OPENRW; + file_tmp -> fileloc = 0; + + RFCNB_Free_Pkt(pkt); /* Free up this space */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Create succeeded, FID = %i\n", file_tmp -> fid); +#endif + + return(file_tmp); + +} + +/* Delete the file passed in as file_name. */ + +int SMB_Delete(SMB_Tree_Handle tree, char *file_name, WORD search) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; + char *p; + + param_len = strlen(file_name) + 2; + pkt_len = SMB_delet_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_delet_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBunlink; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 1; + + SIVAL(SMB_Hdr(pkt), SMB_delet_sat_offset, search); + SSVAL(SMB_Hdr(pkt), SMB_delet_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_delet_buf_offset); + *p = SMBasciiID; + strcpy(p+1, file_name); + p = p + strlen(file_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Delete request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to delete request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Delete failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "File %s deleted successfully.\n", file_name); +#endif /* DEBUG */ + + RFCNB_Free_Pkt(pkt); + + return(0); +} + +/* Create the directory passed in as dir_name */ + +int SMB_Create_Dir(SMB_Tree_Handle tree, char *dir_name) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; + char *p; + + param_len = strlen(dir_name) + 2; /* + null and + asciiID */ + pkt_len = SMB_creatdir_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_creatdir_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBmkdir; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_creatdir_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_creatdir_buf_offset); + *p = SMBasciiID; + strcpy(p+1, dir_name); + p = p + strlen(dir_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Create Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Create Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Create_Dir failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "Directory %s created successfully.\n", dir_name); +#endif + + RFCNB_Free_Pkt(pkt); + + return(0); +} + +/* Delete the directory passed as dir_name, as long as it is empty ... */ + +int SMB_Delete_Dir(SMB_Tree_Handle tree, char *dir_name) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; + char *p; + + param_len = strlen(dir_name) + 2; /* + null and + asciiID */ + pkt_len = SMB_deletdir_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_deletdir_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBrmdir; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_deletdir_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_deletdir_buf_offset); + *p = SMBasciiID; + strcpy(p+1, dir_name); + p = p + strlen(dir_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Delete Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Delete Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Delete_Dir failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "Directory %s deleted successfully.\n", dir_name); +#endif + + RFCNB_Free_Pkt(pkt); + + return(0); +} + +/* Check for the existence of the directory in dir_name */ + +int SMB_Check_Dir(SMB_Tree_Handle tree, char *dir_name) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; + char *p; + + param_len = strlen(dir_name) + 2; /* + null and + asciiID */ + pkt_len = SMB_checkdir_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_checkdir_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBchkpth; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_checkdir_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_checkdir_buf_offset); + *p = SMBasciiID; + strcpy(p+1, dir_name); + p = p + strlen(dir_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Check Dir Path request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Check Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Check_Dir failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "Directory %s checked successfully.\n", dir_name); +#endif + + RFCNB_Free_Pkt(pkt); + + return(0); +} + +/* Search directory for the files listed ... Relative to the TID in the */ +/* Con Handle. Return number of Dir Ents returned as the result. */ + +int SMB_Search(SMB_Tree_Handle tree, + char *dir_name, + WORD search, + SMB_CP_dirent *dirents, + int direntc, + char *resumekey, + int resumekey_len) + +{ struct RFCNB_Pkt *pkt, *recv_pkt; + int pkt_len, param_len, recv_param_len, recv_pkt_len, ret_count, i; + char *p; + + param_len = strlen(dir_name) + 2 + resumekey_len + 3; /* You have to know */ + pkt_len = SMB_search_len + param_len; + + recv_param_len = direntc * SMB_searchr_dirent_len + 3; + recv_pkt_len = SMB_searchr_len + recv_param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + recv_pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(recv_pkt_len); + + if (recv_pkt == NULL) { /* Really should do some error handling */ + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_search_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsearch; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + + /* Tell server we known about non-dos names and extended attibutes */ + + SSVAL(SMB_Hdr(pkt), SMB_hdr_flg2_offset, + (SMB_FLG2_NON_DOS | SMB_FLG2_EXT_ATR)); + + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 2; + + SSVAL(SMB_Hdr(pkt), SMB_search_mdc_offset, direntc); /* How many we want */ + SSVAL(SMB_Hdr(pkt), SMB_search_atr_offset, search); + SSVAL(SMB_Hdr(pkt), SMB_search_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_search_buf_offset); + *p = SMBasciiID; + strcpy(p+1, dir_name); + p = p + strlen(dir_name) + 2; /* Skip the null */ + + + + *p = SMBvariableblockID; + p = p + 1; + + /* And now the resume key */ + + SSVAL(p, 0, resumekey_len); + + p = p + 2; + + bcopy(resumekey, p, resumekey_len); + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending search request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + RFCNB_Free_Pkt(recv_pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, recv_pkt, recv_pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Check Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + RFCNB_Free_Pkt(recv_pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Check_Dir failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(recv_pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + RFCNB_Free_Pkt(recv_pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); /* Should clean up ... */ + + } + + /* Now copy the results into the user's structure */ + + ret_count = SVAL(SMB_Hdr(recv_pkt), SMB_searchr_dec_offset); + + p = SMB_Hdr(recv_pkt) + SMB_searchr_buf_offset + 3; + + /* Hmmm, should check that we have the right number of bytes ... */ + + for (i = 0; i < ret_count; i++) { + + bcopy(p, dirents[i].resume_key, 21); + + p = p + 21; + + dirents[i].file_attributes = (unsigned char)*p; + + p = p + 1; + + dirents[i].date_time = IVAL(p, 0); /* Should this be IVAL? */ + + p = p + 4; + + dirents[i].size = IVAL(p, 0); + + p = p + 4; + + bcopy(p, dirents[i].filename, 13); /* Copy in file name */ + + p = p + 13; + + } + + return(ret_count); + +} |