[2.2 patch] client/client.c: reget and reput commands

Josef Zlomek josef.zlomek at email.cz
Mon Aug 19 08:54:35 GMT 2002


Hello!

I have written the reget and reput commands for samba 2.2.
When user gets/puts a large file and the connection brokes
the user is unhappy (s)he has to transfer the file from the beginning.
So with this patch (s)he can use command reget/reput that
will continue in the transfer, i.e. it will seek both in local and remote file
to position of the end of target file and continue with the transfer from this position.
Although the local networks are fast, it takes several minutes to tranfer
a 650 MB large file (e.g. ISO image) so I think this commands are useful.

While writing these commands I found something that confuses me:
the get and put commands are similar so one would thing that get and put would
use similar functions.  But function writefile (that is used by command get)
uses function write, and function readfile (that is used by command get) uses
function fread.  I think that both functions should use either
open/read/write/close, or fopen/fread/fwrite/fclose.
Because of this, I'm not sending the patch for samba 3.0 right now, because
seek is not supported by XFILE (that is used in 3.0's put) yet.  I would like
to know first whether it is better to use syscalls in both get and put,
or write x_fseek for reput.

Patch follows.

Josef Zlomek

Index: source/client/client.c
===================================================================
RCS file: /cvsroot/samba/source/client/client.c,v
retrieving revision 1.148.2.28
diff -u -r1.148.2.28 client.c
--- source/client/client.c	14 May 2002 14:00:49 -0000	1.148.2.28
+++ source/client/client.c	19 Aug 2002 12:49:11 -0000
@@ -57,6 +57,7 @@
 /* value for unused fid field in trans2 secondary request */
 #define FID_UNUSED (0xFFFF)
 
+BOOL restart_at_file_end = False;
 time_t newer_than = 0;
 int archive_level = 0;
 
@@ -638,7 +639,7 @@
   ****************************************************************************/
 static void do_get(char *rname,char *lname)
 {  
-	int handle=0,fnum;
+	int handle = -1, fnum;
 	BOOL newhandle = False;
 	char *data;
 	struct timeval tp_start;
@@ -646,6 +647,7 @@
 	uint16 attr;
 	size_t size;
 	off_t nread = 0;
+	off_t start = 0;
 
 	GetTimeOfDay(&tp_start);
 
@@ -663,7 +665,18 @@
 	if(!strcmp(lname,"-")) {
 		handle = fileno(stdout);
 	} else {
-		handle = sys_open(lname,O_WRONLY|O_CREAT|O_TRUNC,0644);
+		if (restart_at_file_end) {
+			handle = sys_open(lname,O_WRONLY|O_CREAT,0644);
+			if (handle >= 0) {
+				start = sys_lseek(handle, 0, SEEK_END);
+				if (start == -1) {
+					DEBUG(0,("Error seeking local file\n"));
+					return;
+				}
+			}
+		}
+		if (handle < 0)
+			handle = sys_open(lname,O_WRONLY|O_CREAT|O_TRUNC,0644);
 		newhandle = True;
 	}
 	if (handle < 0) {
@@ -690,7 +703,7 @@
 	}
 
 	while (1) {
-		int n = cli_read(cli, fnum, data, nread, read_size);
+		int n = cli_read(cli, fnum, data, nread + start, read_size);
 
 		if (n <= 0) break;
  
@@ -702,7 +715,7 @@
 		nread += n;
 	}
 
-	if (nread < size) {
+	if (nread + start < size) {
 		DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
                rname, (long)nread));
 	}
@@ -767,6 +780,17 @@
 
 
 /****************************************************************************
+  get a file restarting at end of local file
+  ****************************************************************************/
+static void cmd_reget(void)
+{
+	restart_at_file_end = True;
+	cmd_get();
+	restart_at_file_end = False;
+}
+
+
+/****************************************************************************
   do a mget operation on one file
   ****************************************************************************/
 static void do_mget(file_info *finfo)
@@ -1015,16 +1039,31 @@
   ****************************************************************************/
 static void do_put(char *rname,char *lname)
 {
-	int fnum;
+	int fnum = -1;
 	FILE *f;
-	int nread=0;
+	size_t nread = 0;
+	size_t start = 0;
 	char *buf=NULL;
 	int maxwrite=io_bufsize;
 	
 	struct timeval tp_start;
 	GetTimeOfDay(&tp_start);
 
-	fnum = cli_open(cli, rname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+	if (restart_at_file_end) {
+		fnum = cli_open(cli, rname, O_RDWR|O_CREAT, DENY_NONE);
+		if (fnum >= 0) {
+			if (!cli_qfileinfo(cli, fnum, NULL, &start,
+					   NULL, NULL, NULL, NULL, NULL) &&
+			    !cli_getattrE(cli, fnum, NULL, &start,
+					  NULL, NULL, NULL)) {
+				DEBUG(0,("getattrib: %s\n",cli_errstr(cli)));
+				return;
+			}
+		}
+	}
+	if (fnum == -1) {
+		fnum = cli_open(cli, rname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+	}
   
 	if (fnum == -1) {
 		DEBUG(0,("%s opening remote file %s\n",cli_errstr(cli),rname));
@@ -1038,6 +1077,12 @@
 		/* size of file is not known */
 	} else {
 		f = sys_fopen(lname,"r");
+		if (f != NULL && restart_at_file_end) {
+			if (sys_fseek(f, start, SEEK_SET) == -1) {
+				DEBUG(0,("Error seeking local file\n"));
+				return;
+			}
+		}
 	}
 
 	if (!f) {
@@ -1066,7 +1111,7 @@
 			break;
 		}
 
-		ret = cli_write(cli, fnum, 0, buf, nread, n);
+		ret = cli_write(cli, fnum, 0, buf, nread + start, n);
 
 		if (n != ret) {
 			DEBUG(0,("Error writing file: %s\n", cli_errstr(cli)));
@@ -1151,6 +1196,18 @@
 	do_put(rname,lname);
 }
 
+
+/****************************************************************************
+  put a file restarting at end of local file
+  ****************************************************************************/
+static void cmd_reput(void)
+{
+	restart_at_file_end = True;
+	cmd_put();
+	restart_at_file_end = False;
+}
+
+
 /*************************************
   File list structure
 *************************************/
@@ -1920,7 +1977,9 @@
   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
+  {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},



More information about the samba-technical mailing list