return NT_STATUS_OK;
}
+/*
+ * Re-order a known good @GMT-token path.
+ */
+
+static NTSTATUS rearrange_snapshot_path(struct smb_filename *smb_fname,
+ char *startp,
+ char *endp)
+{
+ size_t endlen = 0;
+ size_t gmt_len = endp - startp;
+ char gmt_store[gmt_len + 1];
+ char *parent = NULL;
+ const char *last_component = NULL;
+ char *newstr;
+ bool ret;
+
+ DBG_DEBUG("|%s| -> ", smb_fname->base_name);
+
+ /* Save off the @GMT-token. */
+ memcpy(gmt_store, startp, gmt_len);
+ gmt_store[gmt_len] = '\0';
+
+ if (*endp == '/') {
+ /* Remove any trailing '/' */
+ endp++;
+ }
+
+ if (*endp == '\0') {
+ /*
+ * @GMT-token was at end of path.
+ * Remove any preceeding '/'
+ */
+ if (startp > smb_fname->base_name && startp[-1] == '/') {
+ startp--;
+ }
+ }
+
+ /* Remove @GMT-token from the path. */
+ endlen = strlen(endp);
+ memmove(startp, endp, endlen + 1);
+
+ /* Split the remaining path into components. */
+ ret = parent_dirname(smb_fname,
+ smb_fname->base_name,
+ &parent,
+ &last_component);
+ if (ret == false) {
+ /* Must terminate debug with \n */
+ DBG_DEBUG("NT_STATUS_NO_MEMORY\n");
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ISDOT(parent)) {
+ if (last_component[0] == '\0') {
+ newstr = talloc_strdup(smb_fname,
+ gmt_store);
+ } else {
+ newstr = talloc_asprintf(smb_fname,
+ "%s/%s",
+ gmt_store,
+ last_component);
+ }
+ } else {
+ newstr = talloc_asprintf(smb_fname,
+ "%s/%s/%s",
+ gmt_store,
+ parent,
+ last_component);
+ }
+
+ TALLOC_FREE(parent);
+ TALLOC_FREE(smb_fname->base_name);
+ smb_fname->base_name = newstr;
+
+ DBG_DEBUG("|%s|\n", newstr);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Canonicalize any incoming pathname potentially containining
+ * a @GMT-token into a path that looks like:
+ *
+ * @GMT-YYYY-MM-DD-HH-MM-SS/path/name/components/last_component
+ *
+ * Leaves single path @GMT-token -component alone:
+ *
+ * @GMT-YYYY-MM-DD-HH-MM-SS -> @GMT-YYYY-MM-DD-HH-MM-SS
+ *
+ * Eventually when struct smb_filename is updated and the VFS
+ * ABI is changed this will remove the @GMT-YYYY-MM-DD-HH-MM-SS
+ * and store in the struct smb_filename as a struct timeval field
+ * instead.
+ */
+
+static NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname)
+{
+ char *startp = strchr_m(smb_fname->base_name, '@');
+ char *endp = NULL;
+ struct tm tm;
+
+ if (startp == NULL) {
+ /* No @ */
+ return NT_STATUS_OK;
+ }
+
+ startp = strstr_m(startp, "@GMT-");
+ if (startp == NULL) {
+ /* No @ */
+ return NT_STATUS_OK;
+ }
+
+ if ((startp > smb_fname->base_name) && (startp[-1] != '/')) {
+ /* the GMT-token does not start a path-component */
+ return NT_STATUS_OK;
+ }
+
+ endp = strptime(startp, GMT_FORMAT, &tm);
+ if (endp == NULL) {
+ /* Not a valid timestring. */
+ return NT_STATUS_OK;
+ }
+
+ if ( endp[0] == '\0') {
+ return rearrange_snapshot_path(smb_fname,
+ startp,
+ endp);
+ }
+
+ if (endp[0] != '/') {
+ /*
+ * It is not a complete path component, i.e. the path
+ * component continues after the gmt-token.
+ */
+ return NT_STATUS_OK;
+ }
+
+ return rearrange_snapshot_path(smb_fname,
+ startp,
+ endp);
+}
+
/****************************************************************************
This routine is called to convert names from the dos namespace to unix
namespace. It needs to handle any case conversions, mangling, format changes,
goto err;
}
+ /* Canonicalize any @GMT- paths. */
+ if (posix_pathnames == false) {
+ status = canonicalize_snapshot_path(smb_fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto err;
+ }
+ }
+
/*
* Large directory fix normalization. If we're case sensitive, and
* the case preserving parameters are set to "no", normalize the case of