[vhffs-dev] [1603] added an option on the slave to preserve owners, groups and permissions

[ Thread Index | Date Index | More vhffs.org/vhffs-dev Archives ]


Revision: 1603
Author:   gradator
Date:     2010-05-09 07:29:22 +0200 (Sun, 09 May 2010)
Log Message:
-----------
added an option on the slave to preserve owners, groups and permissions

Modified Paths:
--------------
    trunk/vhffs-fssync/vhffsfssync_master.c
    trunk/vhffs-fssync/vhffsfssync_slave.c

Modified: trunk/vhffs-fssync/vhffsfssync_master.c
===================================================================
--- trunk/vhffs-fssync/vhffsfssync_master.c	2010-04-26 15:44:54 UTC (rev 1602)
+++ trunk/vhffs-fssync/vhffsfssync_master.c	2010-05-09 05:29:22 UTC (rev 1603)
@@ -221,7 +221,7 @@
 int vhffsfssync_net_file_close(vhffsfssync_conn *conn, vhffsfssync_net_file *file);
 int vhffsfssync_net_remove_file(vhffsfssync_conn *conn, char *pathname);
 void vhffsfssync_net_broadcast_file(char *pathname);
-char *vhffsfssync_net_parent_mtime(char *pathname);
+char *vhffsfssync_net_parent_attrib(char *pathname);
 int vhffsfssync_net_send(vhffsfssync_conn *conn);
 int vhffsfssync_net_recv_event(vhffsfssync_conn *conn, char *event);
 int vhffsfssync_net_parse(vhffsfssync_conn *conn);
@@ -416,6 +416,10 @@
 	vhffsfssync_net_message_file *msg;
 	uint32_t maxprio = -1;  // 4294967295
 	vhffsfssync_net_file *file;
+	struct stat st;
+	st.st_mode=0;
+	st.st_uid=-1;
+	st.st_gid=-1;
 
 	if(!conn || !pathname)
 		return -1;
@@ -424,9 +428,13 @@
 	if(!file)
 		return -1;
 
+	if( fstat(fileno(file->file_stream), &st) < 0 )  {
+		fprintf(stderr, "fstat() failed on %s: %s\n", file->file_pathname, strerror(errno));
+	}
+
 	//printf("%d SENDING FILE %s\n", conn->fd, pathname);
-	vhffsfssync_net_send_event(conn, g_strdup_printf("open%c%s%c", '\0', pathname, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-	vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+	vhffsfssync_net_send_event(conn, g_strdup_printf("open%c%s%c%d%c%d%c%d%c", '\0', pathname, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+	vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_attrib(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 
 	// the size of the file is the priority (small files are sent with more priority)
 	// but don't set the priority too low, low value can be used for anything else
@@ -444,7 +452,7 @@
 
 void vhffsfssync_net_destroy_file(vhffsfssync_conn *conn, vhffsfssync_net_message_file *filemsg)  {
 	struct stat st;
-	st.st_mtime=0;
+	st.st_mtime=-1;
 
 	conn->messages = g_list_remove(conn->messages, (vhffsfssync_net_message*)filemsg);
 	conn->messages_num--;
@@ -570,11 +578,14 @@
 }
 
 
-char *vhffsfssync_net_parent_mtime(char *pathname)  {
+char *vhffsfssync_net_parent_attrib(char *pathname)  {
 	char *cur;
 	struct stat st;
 	char *ret;
-	st.st_mtime = 0;
+	st.st_mtime=-1;
+	st.st_mode=0;
+	st.st_uid=-1;
+	st.st_gid=-1;
 
 	for( cur = pathname+strlen(pathname) ; *cur != '/' ; cur-- );
 	*cur = '\0';
@@ -587,7 +598,7 @@
 		}
 	}
 
-	ret = g_strdup_printf("mtime%c%s%c%ld%c", '\0', pathname, '\0', st.st_mtime, '\0');
+	ret = g_strdup_printf("attrib%c%s%c%ld%c%d%c%d%c%d%c", '\0', pathname, '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0');
 	*cur = '/';
 	return ret;
 }
@@ -854,16 +865,16 @@
 				vhffsfssync_net_send_file(conn, pathname);
 			}
 			else if( S_ISDIR(st.st_mode) )  {
-				vhffsfssync_net_send_event(conn, g_strdup_printf("mkdir%c%s%c%ld%c", '\0', pathname, '\0', st.st_mtime, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-				vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+				vhffsfssync_net_send_event(conn, g_strdup_printf("mkdir%c%s%c%ld%c%d%c%d%c%d%c", '\0', pathname, '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+				vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_attrib(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 			}
 			else if( S_ISLNK(st.st_mode) )  {
 				char *linkto;
 				linkto = malloc(st.st_size +1);
 				if( readlink(pathname, linkto, st.st_size) >= 0 )  {
 					linkto[st.st_size] = '\0';
-					vhffsfssync_net_send_event(conn, g_strdup_printf("symlink%c%s%c%s%c%ld%c", '\0', pathname, '\0', linkto, '\0', st.st_mtime, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-					vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+					vhffsfssync_net_send_event(conn, g_strdup_printf("symlink%c%s%c%s%c%ld%c%d%c%d%c", '\0', pathname, '\0', linkto, '\0', st.st_mtime, '\0', st.st_uid, '\0', st.st_gid, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+					vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_attrib(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 				}
 				free(linkto);
 			}
@@ -1044,10 +1055,20 @@
 		d = opendir(pathname);
 		if(d) {
 			struct dirent *dir;
-			GString *msg = g_string_sized_new(1024);
+			GString *msg;
+			struct stat st;
+			st.st_mtime=-1;
+			st.st_mode=0;
+			st.st_uid=-1;
+			st.st_gid=-1;
 
-			g_string_append_printf(msg, "ls%c%s%c", '\0', pathname, '\0' );
+			if(lstat(pathname, &st) )  {
+				fprintf(stderr, "cannot lstat() '%s': %s\n", pathname, strerror(errno));
+			}
 
+			msg = g_string_sized_new(1024);
+			g_string_append_printf(msg, "ls%c%s%c%ld%c%d%c%d%c%d%c", '\0', pathname, '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0');
+
 			while( (dir = readdir(d)) ) {
 				if( strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..") ) {
 					char *path = g_strdup_printf("%s/%s", pathname, dir->d_name);
@@ -1057,13 +1078,13 @@
 						if( S_ISDIR(st.st_mode) )  {
 							// register a new directory
 							ldirs = g_list_append(ldirs, g_strdup(path));
-							g_string_append_printf(msg, "%s%cdir%c0%c%ld%c", dir->d_name, '\0', '\0', '\0', st.st_mtime, '\0');
+							g_string_append_printf(msg, "%s%cdir%c0%c%ld%c%d%c%d%c%d%c", dir->d_name, '\0', '\0', '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0');
 						}
 						else if( S_ISREG(st.st_mode) )  {
-							g_string_append_printf(msg, "%s%cfile%c%lld%c%ld%c", dir->d_name, '\0', '\0', (long long int)st.st_size, '\0', st.st_mtime, '\0');
+							g_string_append_printf(msg, "%s%cfile%c%lld%c%ld%c%d%c%d%c%d%c", dir->d_name, '\0', '\0', (long long int)st.st_size, '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0');
 						}
 						else if( S_ISLNK(st.st_mode) )  {
-							g_string_append_printf(msg, "%s%clink%c%lld%c%ld%c", dir->d_name, '\0', '\0', (long long int)st.st_size, '\0', st.st_mtime, '\0');
+							g_string_append_printf(msg, "%s%clink%c%lld%c%ld%c%d%c%d%c%d%c", dir->d_name, '\0', '\0', (long long int)st.st_size, '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0');
 						}
 						/* we don't need other file types (chr, block, fifo, socket, ...) */
 					}
@@ -1193,7 +1214,7 @@
 /* -- inotify stuff -- */
 
 char *vhffsfssync_pathname(vhffsfssync_watch *watch, const char *filename)  {
-	
+
 	GString *pathname = g_string_sized_new(256);
 	char **dirnames, **curnames, **endnames;
 	uint32_t a;
@@ -1249,7 +1270,7 @@
 		free(pathname);
 		return NULL;
 	}
- 
+
  	if( (watch = g_hash_table_lookup(vhffsfssync_wd_to_watch, &wd)) ) {
 
 		// this was already watched, update name and reattach to the new parent
@@ -1343,7 +1364,7 @@
 		conns = g_list_next(conns);
 		vhffsfssync_net_remove_file(conn, pathname);
 		vhffsfssync_net_send_event(conn, g_strdup_printf("remove%c%s%c", '\0', pathname, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-		vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+		vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_attrib(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 	}
 
 	free(pathname);
@@ -1364,8 +1385,8 @@
 			printf("==> CREATE %s\n", pathname);
 #endif
 			if(!st.st_size)  {
-				vhffsfssync_net_broadcast_event( g_strdup_printf("create%c%s%c%ld%c", '\0', pathname, '\0', st.st_mtime, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-				vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+				vhffsfssync_net_broadcast_event( g_strdup_printf("create%c%s%c%ld%c%d%c%d%c%d%c", '\0', pathname, '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+				vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_attrib(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 			}
 			else {
 				vhffsfssync_net_broadcast_file(pathname);
@@ -1378,8 +1399,8 @@
 			printf("==> MKDIR %s\n", pathname);
 #endif
 			newwatch = vhffsfssync_add_watch(inotifyfd, watch, filename, VHFFSFSSYNC_WATCH_MASK);
-			vhffsfssync_net_broadcast_event( g_strdup_printf("mkdir%c%s%c%ld%c", '\0', pathname, '\0', st.st_mtime, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-			vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+			vhffsfssync_net_broadcast_event( g_strdup_printf("mkdir%c%s%c%ld%c%d%c%d%c%d%c", '\0', pathname, '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+			vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_attrib(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 			/* there is a short delay between the mkdir() and the add_watch(),
 			   we need to send events about the data which have already been written */
 			vhffsfssync_fake_events_recursively( inotifyfd, newwatch );
@@ -1395,8 +1416,8 @@
 #if DEBUG_INOTIFY
 				printf("==> SYMLINK %s -> %s\n", pathname, linkto);
 #endif
-				vhffsfssync_net_broadcast_event( g_strdup_printf("symlink%c%s%c%s%c%ld%c", '\0', pathname, '\0', linkto, '\0', st.st_mtime, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-				vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+				vhffsfssync_net_broadcast_event( g_strdup_printf("symlink%c%s%c%s%c%ld%c%d%c%d%c", '\0', pathname, '\0', linkto, '\0', st.st_mtime, '\0', st.st_uid, '\0', st.st_gid, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+				vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_attrib(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 			}
 			free(linkto);
 			if(ret < 0) {
@@ -1466,7 +1487,7 @@
 		printf("IN_ATTRIB\n");
 #endif
 		if(! lstat(pathname, &st) )  {
-			vhffsfssync_net_broadcast_event( g_strdup_printf("mtime%c%s%c%ld%c", '\0', pathname, '\0', st.st_mtime, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+			vhffsfssync_net_broadcast_event( g_strdup_printf("attrib%c%s%c%ld%c%d%c%d%c%d%c", '\0', pathname, '\0', st.st_mtime, '\0', st.st_mode&07777, '\0', st.st_uid, '\0', st.st_gid, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 		}
 		else {
 			if(errno == ENOENT) {
@@ -1555,12 +1576,12 @@
 			free(tmp);
 #endif
 			if( vhffsfssync_cookie.isdir )  {
-				
+
 				char *frompathname = vhffsfssync_pathname(vhffsfssync_cookie.watch, vhffsfssync_cookie.filename);
 				vhffsfssync_add_watch(inotifyfd, watch, event->name, VHFFSFSSYNC_WATCH_MASK);
 				vhffsfssync_net_broadcast_event( g_strdup_printf("move%c%s%c%s%c", '\0', frompathname, '\0', pathname, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-				vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(frompathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
-				vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+				vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_attrib(frompathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+				vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_attrib(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
 				free(frompathname);
 			}
 			else {
@@ -1598,7 +1619,7 @@
 int vhffsfssync_fake_events_recursively(int inotifyfd, vhffsfssync_watch *watch)  {
 	DIR *d;
 	char *pathname;
-	
+
 	pathname = vhffsfssync_pathname(watch, NULL);
 	d = opendir(pathname);
 	free(pathname);

Modified: trunk/vhffs-fssync/vhffsfssync_slave.c
===================================================================
--- trunk/vhffs-fssync/vhffsfssync_slave.c	2010-04-26 15:44:54 UTC (rev 1602)
+++ trunk/vhffs-fssync/vhffsfssync_slave.c	2010-05-09 05:29:22 UTC (rev 1603)
@@ -90,14 +90,15 @@
 
 // events protos
 int vhffsfssync_remove(char *pathname);
-int vhffsfssync_mkdir(char *pathname, mode_t mode, int long long mtime);
-int vhffsfssync_checkfile(vhffsfssync_conn *conn, char *path, char *type, int long long size, int long long mtime);
+int vhffsfssync_mkdir(char *pathname, int long long mtime, int mode, int uid, int gid);
+int vhffsfssync_checkfile(vhffsfssync_conn *conn, char *path, char *type, int long long size, int long long mtime, int mode, int uid, int gid);
 int vhffsfssync_event(vhffsfssync_conn *conn, char *event);
 int vhffsfssync_parse(vhffsfssync_conn *conn);
 
 // misc
 double vhffsfssync_time();
 static void usage_exit(int ret_code, char *progname);
+int vhffsfssync_preserve;
 
 /* ------------------------------------------------------------ */
 
@@ -261,7 +262,7 @@
 
 
 // the content of pathname is modified
-int vhffsfssync_mkdir(char *pathname, mode_t mode, int long long mtime)  {
+int vhffsfssync_mkdir(char *pathname, int long long mtime, int mode, int uid, int gid)  {
 	char *cur, *dirs[64];
 	int i, fd, fd_, argc;
 
@@ -288,13 +289,24 @@
 		}
 	}
 	if(fd >= 0) {
-		if(mtime && i == argc) {
-			struct timeval tv[2];
-			tv[0].tv_sec = (time_t)mtime;
-			tv[0].tv_usec = 0;
-			tv[1].tv_sec = (time_t)mtime;
-			tv[1].tv_usec = 0;
-			futimes(fd, &tv[0]);
+		if(i == argc) {
+			if(mtime>=0) {
+				struct timeval tv[2];
+				tv[0].tv_sec = (time_t)mtime;
+				tv[0].tv_usec = 0;
+				tv[1].tv_sec = (time_t)mtime;
+				tv[1].tv_usec = 0;
+				futimes(fd, &tv[0]);
+			}
+
+			if(vhffsfssync_preserve && uid>=0)  {
+				if( fchmod(fd, mode) ) {
+					fprintf(stderr, "fchmod() failed on %s: %s\n", pathname, strerror(errno));
+				}
+				if( fchown(fd, uid, gid) ) {
+					fprintf(stderr, "fchown() failed on %s: %s\n", pathname, strerror(errno));
+				}
+			}
 		}
 		close(fd);
 	}
@@ -305,7 +317,7 @@
 #endif
 
 
-int vhffsfssync_checkfile(vhffsfssync_conn *conn, char *path, char *type, int long long size, int long long mtime) {
+int vhffsfssync_checkfile(vhffsfssync_conn *conn, char *path, char *type, int long long size, int long long mtime, int mode, int uid, int gid) {
 	gboolean fetch = FALSE;
 	struct stat st;
 
@@ -318,11 +330,9 @@
 		if( S_ISDIR(st.st_mode) )  {
 			type_ = "dir";
 		}
-
 		else if( S_ISREG(st.st_mode) )  {
 			type_ = "file";
 		}
-
 		else if( S_ISLNK(st.st_mode) )  {
 			type_ = "link";
 		}
@@ -340,6 +350,27 @@
 		else if(st.st_mtime != mtime) {
 			fetch = TRUE;
 		}
+
+		if(!fetch && vhffsfssync_preserve) {
+			if(!S_ISLNK(st.st_mode) && (st.st_mode&07777) != mode) {
+#ifndef CHECK
+				if( chmod(path, mode) ) {
+					fprintf(stderr, "chmod() failed on %s: %s\n", path, strerror(errno));
+				}
+#else
+				printf("%s mode is not synched\n", path );
+#endif
+			}
+			if(st.st_uid != uid || st.st_gid != gid) {
+#ifndef CHECK
+				if( lchown(path, uid, gid) ) {
+					fprintf(stderr, "lchown() failed on %s: %s\n", path, strerror(errno));
+				}
+#else
+				printf("%s uid or gid are not synched\n", path );
+#endif
+			}
+		}
 	}
 	else {
 		if(errno == ENOENT) {
@@ -397,9 +428,15 @@
 	else if(!strcmp(args[0], "create")) {
 		char *pathname = args[1];
 		int long long mtime = atoll(args[2]);
+		int mode = atol(args[3]);
+		int uid = atol(args[4]);
+		int gid = atol(args[5]);
 		int fd;
 
-		fd = open(pathname, O_CREAT|O_WRONLY|O_TRUNC, 0644);
+		if(!vhffsfssync_preserve || uid<0)
+			mode = 0644;
+
+		fd = open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode);
 		if(fd >= 0) {
 			struct timeval tv[2];
 
@@ -412,6 +449,15 @@
 				fprintf(stderr, "futimes() failed on %s: %s\n", pathname, strerror(errno));
 			}
 
+			if(vhffsfssync_preserve && uid>=0)  {
+				if( fchmod(fd, mode) ) {
+					fprintf(stderr, "fchmod() failed on %s: %s\n", pathname, strerror(errno));
+				}
+				if( fchown(fd, uid, gid) ) {
+					fprintf(stderr, "fchown() failed on %s: %s\n", pathname, strerror(errno));
+				}
+			}
+
 			close(fd);
 		}
 		else {
@@ -420,12 +466,30 @@
 	}
 	else if(!strcmp(args[0], "open")) {
 		char *pathname = args[1];
+		int mode = atol(args[2]);
+		int uid = atol(args[3]);
+		int gid = atol(args[4]);
 		int fd;
 
+ 		if(!vhffsfssync_preserve || uid<0)
+			mode = 0644;
+
 		if( !g_hash_table_lookup(conn->openfiles, pathname) ) {
-			fd = open(pathname, O_CREAT|O_WRONLY|O_TRUNC, 0644);
+
+			fd = open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode);
 			if(fd >= 0) {
-				FILE *f = fdopen(fd, "w");
+				FILE *f;
+
+				if(vhffsfssync_preserve && uid>=0)  {
+					if( fchmod(fd, mode) ) {
+						fprintf(stderr, "fchmod() failed on %s: %s\n", pathname, strerror(errno));
+					}
+					if( fchown(fd, uid, gid) ) {
+						fprintf(stderr, "fchown() failed on %s: %s\n", pathname, strerror(errno));
+					}
+				}
+
+				f = fdopen(fd, "w");
 				if(f) {
 					g_hash_table_insert(conn->openfiles, strdup(pathname), f);
 				}
@@ -446,17 +510,18 @@
 
 		f = g_hash_table_lookup(conn->openfiles, pathname);
 		if(f) {
-			struct timeval tv[2];
-
 			fflush(f);
 
-			tv[0].tv_sec = (time_t)mtime;
-			tv[0].tv_usec = 0;
-			tv[1].tv_sec = (time_t)mtime;
-			tv[1].tv_usec = 0;
+			if(mtime>=0) {
+				struct timeval tv[2];
+				tv[0].tv_sec = (time_t)mtime;
+				tv[0].tv_usec = 0;
+				tv[1].tv_sec = (time_t)mtime;
+				tv[1].tv_usec = 0;
 
-			if( futimes(fileno(f), tv) ) {
-				fprintf(stderr, "futimes() failed on %s: %s\n", pathname, strerror(errno));
+				if( futimes(fileno(f), tv) ) {
+					fprintf(stderr, "futimes() failed on %s: %s\n", pathname, strerror(errno));
+				}
 			}
 		}
 		g_hash_table_remove(conn->openfiles, pathname);
@@ -464,13 +529,18 @@
 	else if(!strcmp(args[0], "mkdir")) {
 		char *path = args[1];
 		int long long mtime = atoll(args[2]);
+		int mode = atol(args[3]);
+		int uid = atol(args[4]);
+		int gid = atol(args[5]);
 
-		vhffsfssync_mkdir(path, 0755, mtime);
+		vhffsfssync_mkdir(path, mtime, mode, uid, gid);
 	}
 	else if(!strcmp(args[0], "symlink")) {
 		char *from = args[1];
 		char *to = args[2];
 		int long long mtime = atoll(args[3]);
+		int uid = atol(args[4]);
+		int gid = atol(args[5]);
 		struct stat st;
 
 		if(! lstat(from, &st) )  {
@@ -486,6 +556,12 @@
 			tv[1].tv_usec = 0;
 
 			lutimes(from, &tv[0]);
+
+			if(vhffsfssync_preserve)  {
+				if( lchown(from, uid, gid) ) {
+					fprintf(stderr, "lchown() failed on %s: %s\n", from, strerror(errno));
+				}
+			}
 		}
 	}
 	else if(!strcmp(args[0], "move")) {
@@ -538,25 +614,49 @@
 			conn->chunk_file = NULL;
 		}
 	}
-	else if(!strcmp(args[0], "mtime")) {
+	else if(!strcmp(args[0], "attrib")) {
 		char *pathname = args[1];
 		int long long mtime = atoll(args[2]);
-		struct timeval tv[2];
+		int mode = atol(args[3]);
+		int uid = atol(args[4]);
+		int gid = atol(args[5]);
 
-		tv[0].tv_sec = (time_t)mtime;
-		tv[0].tv_usec = 0;
-		tv[1].tv_sec = (time_t)mtime;
-		tv[1].tv_usec = 0;
+		if(mtime>=0) {
+			struct timeval tv[2];
+			tv[0].tv_sec = (time_t)mtime;
+			tv[0].tv_usec = 0;
+			tv[1].tv_sec = (time_t)mtime;
+			tv[1].tv_usec = 0;
 
-		lutimes(pathname, &tv[0]);
+			lutimes(pathname, &tv[0]);
+		}
+
+		if(vhffsfssync_preserve && uid>=0)  {
+			struct stat st;
+
+			if(! lstat(pathname, &st) )  {
+
+				if( !S_ISLNK(st.st_mode) )  {
+					if( chmod(pathname, mode) ) {
+						fprintf(stderr, "chmod() failed on %s: %s\n", pathname, strerror(errno));
+					}
+				}
+
+				if( lchown(pathname, uid, gid) ) {
+					fprintf(stderr, "lchown() failed on %s: %s\n", pathname, strerror(errno));
+				}
+			}
+		}
 	}
 	else if(!strcmp(args[0], "ls")) {
-		char *root, *root_;
+		char *root = args[1];
+		int long long mtime = atoll(args[2]);
+		int mode = atol(args[3]);
+		int uid = atol(args[4]);
+		int gid = atol(args[5]);
+		char *root_ = strdup(root);
 
-		root = args[1];
-		root_ = strdup(root);
-
-		if(! vhffsfssync_mkdir(root, 0755, 0) ) {
+		if(! vhffsfssync_mkdir(root, mtime, mode, uid, gid) ) {
 			int i;
 			GHashTable *filesindex;
 			DIR *d;
@@ -565,12 +665,12 @@
 			filesindex = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
 
 			// check each file
-			for( i = 2 ; i < argc ; i+=4 ) {
+			for( i = 6 ; i < argc ; i+=7 ) {
 				char *path;
 				g_hash_table_insert(filesindex, args[i], args[i]);
 
 				path = g_strdup_printf("%s/%s", root_, args[i]);
-				vhffsfssync_checkfile(conn, path, args[i+1], atoll(args[i+2]), atoll(args[i+3]) );
+				vhffsfssync_checkfile(conn, path, args[i+1], atoll(args[i+2]), atoll(args[i+3]), atol(args[i+4]), atol(args[i+5]), atol(args[i+6]) );
 				free(path);
 			}
 
@@ -663,7 +763,7 @@
 		ssize_t size = atol(args[3]);
 		conn->chunk_stilltoread = size;
 	}
-	else if(!strcmp(args[0], "mtime")) {
+	else if(!strcmp(args[0], "attrib")) {
 	}
 	else if(!strcmp(args[0], "ls")) {
 		char *root, *root_;
@@ -687,12 +787,12 @@
 			filesindex = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
 
 			// check each file
-			for( i = 2 ; i < argc ; i+=4 ) {
+			for( i = 6 ; i < argc ; i+=7 ) {
 				char *path;
 				g_hash_table_insert(filesindex, args[i], args[i]);
 
 				path = g_strdup_printf("%s/%s", root_, args[i]);
-				vhffsfssync_checkfile(conn, path, args[i+1], atoll(args[i+2]), atoll(args[i+3]) );
+				vhffsfssync_checkfile(conn, path, args[i+1], atoll(args[i+2]), atoll(args[i+3]), atol(args[i+4]), atol(args[i+5]), atol(args[i+6]) );
 				free(path);
 			}
 
@@ -842,6 +942,7 @@
 		"Remote synchronous file-copying tool, this is the client (the slave)\n\n"
 		"  -f, --foreground\tDo not daemonise the client, display errors on the console\n"
 		"  -r, --limit-rate=kB/s\tLimit I/O bandwidth; kBytes per second\n"
+		"  -p, --preserve\tPreserve owners, groups and permissions\n"
 		"  -h, --help\t\tDisplay this help and exit\n"
 		"  -v, --version\t\tOutput version information and exit\n",
 		progname);
@@ -861,6 +962,7 @@
 	char *root = NULL;
 	int limitrate = 0;
 
+	vhffsfssync_preserve = 0;
 #ifdef CHECK
 	foreground = 1;
 #endif
@@ -868,6 +970,7 @@
 	struct option long_options[] = {
 		{ "foreground", no_argument, NULL, 'f' },
 		{ "limit-rate", required_argument, NULL, 'r' },
+		{ "preserve", no_argument, NULL, 'p' },
 		{ "help", no_argument, NULL, 'h' },
 		{ "version", no_argument, NULL, 'v' },
 		{ 0, 0, 0, 0 }
@@ -875,7 +978,7 @@
 
 	while(1) {
 		int option_index = 0, c;
-		c = getopt_long(argc, argv, "fr:hv", long_options, &option_index);
+		c = getopt_long(argc, argv, "fr:phv", long_options, &option_index);
 		if(c == -1)
 			break;
 
@@ -888,6 +991,10 @@
 				limitrate = atoi(optarg)*1000;
 				break;
 
+			case 'p':
+				vhffsfssync_preserve = 1;
+				break;
+
 			case 'h':
 				usage_exit(0, argv[0]);
 
@@ -930,6 +1037,9 @@
 		if(fork()) exit(0);
 	}
 
+	// so that open() and mkdir() will not enforce wanted mode with mode&~umask
+	umask(0);
+
 	/* chdir() to the filesystem to write the data */
 	if( chdir(root) < 0 ) {
 		fprintf(stderr, "cannot chdir() to %s: %s\n", root, strerror(errno));
@@ -937,6 +1047,8 @@
 	}
 	if( chroot(".") < 0 ) {
 		fprintf(stderr, "cannot chroot() to %s: %s\n", root, strerror(errno));
+		// disable permissions, owners and groups preservation if we are not root
+		vhffsfssync_preserve = 0;
 		//return -1;
 	}
 	root = ".";


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/