Latest Time Machine Patch

Kevin Anderson andersonkw2 at gmail.com
Wed Sep 13 01:13:22 UTC 2017


Hello everyone,

Attached is the latest time machine patch with the Avahi support
contributed by Omri and rebased against master. This has been 
stable without any warnings of corrupted backup volumes. 

The only thing that has come up lately is potentially supporting 
setting the avahi hostname rather than the current method of 
using the netbios name so that it would show as lowercase rather
than all capitals. I personally don't have a strong opinion either
way but am open to suggestions.

Depending on the result of the previous question, what remains
left to be done to have this merged?

Thanks,
Kevin Anderson
-------------- next part --------------
diff --git a/docs-xml/manpages/vfs_fruit.8.xml b/docs-xml/manpages/vfs_fruit.8.xml
index c5ffc828fc3..4840b5c6340 100644
--- a/docs-xml/manpages/vfs_fruit.8.xml
+++ b/docs-xml/manpages/vfs_fruit.8.xml
@@ -214,6 +214,38 @@
 	  </varlistentry>
 
 	  <varlistentry>
+	    <term>fruit:time machine = [ yes | no ]</term>
+	    <listitem>
+	      <para>Controls if Time Machine support via the FULLSYNC volume
+	      capability is advertised to clients.</para>
+	      <itemizedlist>
+		<listitem><para><command>no (default)</command> Disables
+		advertising Time Machine support and the FULLSYNC volume
+		capability to clients.</para></listitem>
+
+		<listitem><para><command>yes</command> - Enables advertising
+		Time Machine support and the FULLSYNC volume capability to
+		clients. This is necessary for supporting Time Machine backups
+		from Mac OSX clients. This value advertises the capability
+		and with the options below, fsync's a file at the request of
+		the client.
+		</para></listitem>
+
+	      </itemizedlist>
+
+	      <para>This option enforces the following settings per share (or
+	      for all shares if enabled globally):</para>
+	      <itemizedlist>
+		<listitem><para><command>durable handles = yes</command></para></listitem>
+		<listitem><para><command>kernel oplocks = no</command></para></listitem>
+		<listitem><para><command>kernel share modes = no</command></para></listitem>
+		<listitem><para><command>posix locking = no</command></para></listitem>
+	      </itemizedlist>
+
+	    </listitem>
+	  </varlistentry>
+
+	  <varlistentry>
 	    <term>fruit:metadata = [ stream | netatalk ]</term>
 	    <listitem>
 	      <para>Controls where the OS X metadata stream is stored:</para>
diff --git a/libcli/smb/smb2_create_ctx.h b/libcli/smb/smb2_create_ctx.h
index cb194f5c536..0e0b713e55c 100644
--- a/libcli/smb/smb2_create_ctx.h
+++ b/libcli/smb/smb2_create_ctx.h
@@ -42,5 +42,6 @@
 /* "AAPL" Volume Capabilities bitmap */
 #define SMB2_CRTCTX_AAPL_SUPPORT_RESOLVE_ID 1
 #define SMB2_CRTCTX_AAPL_CASE_SENSITIVE     2
+#define SMB2_CRTCTX_AAPL_FULL_SYNC          4
 
 #endif
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 3ba59967482..6a6c4556aee 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -139,6 +139,7 @@ struct fruit_config_data {
 	bool posix_rename;
 	bool aapl_zero_file_id;
 	const char *model;
+	bool time_machine;
 
 	/*
 	 * Additional options, all enabled by default,
@@ -1549,6 +1550,9 @@ static int init_fruit_config(vfs_handle_struct *handle)
 	config->use_aapl = lp_parm_bool(
 		-1, FRUIT_PARAM_TYPE_NAME, "aapl", true);
 
+	config->time_machine = lp_parm_bool(
+		SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "time machine", false);
+
 	config->unix_info_enabled = lp_parm_bool(
 		-1, FRUIT_PARAM_TYPE_NAME, "nfs_aces", true);
 
@@ -2206,6 +2210,10 @@ static NTSTATUS check_aapl(vfs_handle_struct *handle,
 			break;
 		}
 
+		if (config->time_machine) {
+			caps |= SMB2_CRTCTX_AAPL_FULL_SYNC;
+		}
+
 		SBVAL(p, 0, caps);
 
 		ok = data_blob_append(req, &blob, p, 8);
@@ -2637,6 +2645,14 @@ static int fruit_connect(vfs_handle_struct *handle,
 			"0x0d:0xf00d");
 	}
 
+	if (config->time_machine) {
+		lp_do_parameter(SNUM(handle->conn), "durable handles", "yes");
+		lp_do_parameter(SNUM(handle->conn), "kernel oplocks", "no");
+		lp_do_parameter(SNUM(handle->conn), "kernel share modes", "no");
+		lp_do_parameter(SNUM(handle->conn), "strict sync", "yes");
+		lp_do_parameter(SNUM(handle->conn), "posix locking", "no");
+	}
+
 	return rc;
 }
 
diff --git a/source3/smbd/avahi_register.c b/source3/smbd/avahi_register.c
index c118e61ccc2..b9ad3a75c25 100644
--- a/source3/smbd/avahi_register.c
+++ b/source3/smbd/avahi_register.c
@@ -18,12 +18,23 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+/*
+ * Avahi aborts on allocation failure (OOM),
+ * unless a custom allocator which doesn't do so has been set.
+ *
+ * This is particularly important for the avahi_string_list_*() functions,
+ * which return NULL on allocation failure.
+ * Since it should abort on allocation failure (before returning NULL),
+ * we don't check the result.
+ */
+
 #include "includes.h"
 #include "smbd/smbd.h"
 
 #include <avahi-client/client.h>
 #include <avahi-client/publish.h>
 #include <avahi-common/error.h>
+#include <avahi-common/strlst.h>
 
 struct avahi_state_struct {
 	struct AvahiPoll *poll;
@@ -70,8 +81,13 @@ static void avahi_client_callback(AvahiClient *c, AvahiClientState status,
 	int error;
 
 	switch (status) {
-	case AVAHI_CLIENT_S_RUNNING:
-		DBG_DEBUG("AVAHI_CLIENT_S_RUNNING\n");
+	case AVAHI_CLIENT_S_RUNNING: {
+		int snum;
+		int num_services = lp_numservices();
+		int dk = 0;
+		AvahiStringList *adisk = NULL;
+
+		DEBUG(10, ("avahi_client_callback: AVAHI_CLIENT_S_RUNNING\n"));
 
 		state->entry_group = avahi_entry_group_new(
 			c, avahi_entry_group_callback, state);
@@ -94,15 +110,42 @@ static void avahi_client_callback(AvahiClient *c, AvahiClientState status,
 			break;
 		}
 
-		error = avahi_entry_group_commit(state->entry_group);
-		if (error != AVAHI_OK) {
-			DBG_DEBUG("avahi_entry_group_commit failed: %s\n",
-				  avahi_strerror(error));
+		for (snum = 0; snum < num_services; snum++) {
+			if (lp_snum_ok(snum) &&
+			    lp_parm_bool(snum, "fruit", "time machine", false))
+			{
+				adisk = avahi_string_list_add_printf(
+					    adisk, "dk%d=adVN=%s,adVF=0x82",
+					    dk++, lp_const_servicename(snum));
+			}
+		}
+		if (dk > 0) {
+			adisk = avahi_string_list_add(adisk, "sys=adVF=0x100");
+			error = avahi_entry_group_add_service_strlst(
+				    state->entry_group, AVAHI_IF_UNSPEC,
+				    AVAHI_PROTO_UNSPEC, 0, lp_netbios_name(),
+				    "_adisk._tcp", NULL, NULL, 0, adisk);
+			avahi_string_list_free(adisk);
+			adisk = NULL;
+			if (error != AVAHI_OK) {
+				DBG_DEBUG("avahi_entry_group_add_service_strlst "
+					  "failed: %s\n", avahi_strerror(error));
+				avahi_entry_group_free(state->entry_group);
+				state->entry_group = NULL;
+				break;
+			}
+		}
+
+		if (avahi_entry_group_commit(state->entry_group) < 0) {
+			error = avahi_client_errno(c);
+			DEBUG(10, ("avahi_entry_group_commit failed: "
+				   "%s\n", avahi_strerror(error)));
 			avahi_entry_group_free(state->entry_group);
 			state->entry_group = NULL;
 			break;
 		}
 		break;
+	}
 	case AVAHI_CLIENT_FAILURE:
 		error = avahi_client_errno(c);
 


More information about the samba-technical mailing list