pass-ntfs-stream-paths-to-vfs [plain text]
Index: samba/source/include/fake_file.h
===================================================================
--- samba/source/include/fake_file.h.orig
+++ samba/source/include/fake_file.h
@@ -39,12 +39,4 @@ typedef struct _FAKE_FILE_HANDLE {
void (*free_pd)(void **pd); /* free private_data */
} FAKE_FILE_HANDLE;
-typedef struct _FAKE_FILE {
- const char *name;
- enum FAKE_FILE_TYPE type;
- void *(*init_pd)(TALLOC_CTX *men_ctx);
- void (*free_pd)(void **pd);
-} FAKE_FILE;
-
-
#endif /* _FAKE_FILE_H */
Index: samba/source/smbd/fake_file.c
===================================================================
--- samba/source/smbd/fake_file.c.orig
+++ samba/source/smbd/fake_file.c
@@ -22,11 +22,33 @@
extern struct current_user current_user;
-static FAKE_FILE fake_files[] = {
-#ifdef WITH_QUOTAS
- {FAKE_FILE_NAME_QUOTA_UNIX, FAKE_FILE_TYPE_QUOTA, init_quota_handle, destroy_quota_handle},
-#endif /* WITH_QUOTAS */
- {NULL, FAKE_FILE_TYPE_NONE, NULL, NULL }
+typedef struct _FAKE_FILE {
+ const char *name;
+ const char **streams;
+ enum FAKE_FILE_TYPE type;
+ void *(*init_pd)(TALLOC_CTX *men_ctx);
+ void (*free_pd)(void **pd);
+} FAKE_FILE;
+
+#ifdef WITH_SYS_QUOTAS
+static const char * fake_quota_streams = {
+ ":$Q:$INDEX_ALLOCATION",
+ NULL
+};
+#endif /* WITH_SYS_QUOTAS */
+
+static const FAKE_FILE fake_files[] = {
+#ifdef WITH_SYS_QUOTAS
+ {
+ FAKE_FILE_NAME_QUOTA_UNIX,
+ fake_quota_streams,
+ FAKE_FILE_TYPE_QUOTA,
+ init_quota_handle,
+ destroy_quota_handle
+ },
+#endif /* WITH_SYS_QUOTAS */
+
+ {NULL, NULL, FAKE_FILE_TYPE_NONE, NULL, NULL }
};
/****************************************************************************
@@ -74,24 +96,43 @@ static struct _FAKE_FILE_HANDLE *init_fa
Does this name match a fake filename ?
****************************************************************************/
-enum FAKE_FILE_TYPE is_fake_file(const char *fname)
+static BOOL match_stream_name(const FAKE_FILE * fake_file, const char *stream)
+{
+ if (!stream) {
+ return True;
+ }
+
+ if (fake_file->streams) {
+ const char ** s;
+
+ for (s = fake_files->streams; *s; ++s) {
+ if (strcmp(stream, *s) == 0) {
+ return True;
+ }
+ }
+ }
+
+ return False;
+}
+
+enum FAKE_FILE_TYPE is_fake_file(const char *fname, const char *stream)
{
-#ifdef HAVE_SYS_QUOTAS
int i;
-#endif
if (!fname) {
return FAKE_FILE_TYPE_NONE;
}
-#ifdef HAVE_SYS_QUOTAS
for (i=0;fake_files[i].name!=NULL;i++) {
- if (strncmp(fname,fake_files[i].name,strlen(fake_files[i].name))==0) {
+ if (strcmp(fname, fake_files[i].name) != 0) {
+ continue;
+ }
+
+ if (match_stream_name(&fake_files[i], stream)) {
DEBUG(5,("is_fake_file: [%s] is a fake file\n",fname));
return fake_files[i].type;
}
}
-#endif
return FAKE_FILE_TYPE_NONE;
}
Index: samba/source/smbd/nttrans.c
===================================================================
--- samba/source/smbd/nttrans.c.orig
+++ samba/source/smbd/nttrans.c
@@ -259,6 +259,9 @@ int send_nt_replies(char *outbuf, int bu
/****************************************************************************
Is it an NTFS stream name ?
+ An NTFS file name is <path>.<extention>:<stream name>:<stream type>
+ $DATA can be used as both a stream name and a stream type. A missing stream
+ name or type implies $DATA.
****************************************************************************/
BOOL is_ntfs_stream_name(const char *fname)
@@ -269,6 +272,63 @@ BOOL is_ntfs_stream_name(const char *fna
return (strchr_m(fname, ':') != NULL) ? True : False;
}
+/* Split a path name into filename and stream name components. Canonicalise
+ * such that an implicit $DATA token is always explicit. If the stream name
+ * resolved to the data stream, then that's the same as not specifying a stream
+ * name.
+ *
+ * F => fname=F sname=
+ * F: => fname=F sname=
+ * F:: => fname=F sname=
+ * F:S => fname=F sname=:S:$DATA
+ * F:$DATA => fname=F sname=
+ * F:S: => fname=F sname=:S:$DATA
+ * F:S:$DATA => fname=F sname=:S:$DATA
+ * F:$DATA: => fname=F sname=
+ * F::T => fname=F sname=:$DATA:T
+ * F::$DATA => fname=F sname=
+ * F:S:T => fname=F sname=:S:T
+ * F:$DATA:T => fname=F sname=:$DATA:T
+ * F:$DATA:$DATA => fname=F sname=
+ *
+ */
+NTSTATUS split_ntfs_stream_name(pstring fname, pstring stream)
+{
+ char *sname; /* stream name */
+ char *stype; /* stream type */
+
+ stream[0] = '\0';
+
+ if (lp_posix_pathnames()) {
+ return NT_STATUS_OK;
+ }
+
+ sname = strchr_m(fname, ':');
+ if (!sname) {
+ /* Not a stream. */
+ return NT_STATUS_OK;
+ }
+
+ /* Truncate fname at the stream name separator. */
+ *sname++ = '\0';
+
+ stype = strchr_m(sname, ':');
+ if (stype) {
+ /* Truncate sname at the stream type separator. */
+ *stype++ = '\0';
+ }
+
+ pstr_sprintf(stream, ":%s:%s",
+ (sname && *sname) ? sname : "$DATA",
+ (stype && *stype) ? stype : "$DATA");
+
+ if (StrCaseCmp(stream, ":$DATA:$DATA") == 0) {
+ *stream = '\0';
+ }
+ return NT_STATUS_OK;
+
+}
+
/****************************************************************************
Save case statics.
****************************************************************************/
@@ -611,9 +671,20 @@ int reply_ntcreate_and_X(connection_stru
* Check to see if this is a mac fork of some kind.
*/
- if( is_ntfs_stream_name(fname)) {
- enum FAKE_FILE_TYPE fake_file_type = is_fake_file(fname);
- if (fake_file_type!=FAKE_FILE_TYPE_NONE) {
+ if (is_ntfs_stream_name(fname)) {
+ pstring path;
+ pstring stream;
+ enum FAKE_FILE_TYPE fake_file_type;
+
+ pstrcpy(path, fname);
+ status = split_ntfs_stream_name(path, stream);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(status);
+ }
+
+ fake_file_type = is_fake_file(path, stream);
+ if (fake_file_type == FAKE_FILE_TYPE_QUOTA) {
/*
* Here we go! support for changing the disk quotas --metze
*
@@ -627,7 +698,10 @@ int reply_ntcreate_and_X(connection_stru
fake_file_type, fname);
END_PROFILE(SMBntcreateX);
return result;
- } else {
+ }
+
+ if (!lp_stream_support(SNUM(conn)) ||
+ !(conn->fs_capabilities & FILE_NAMED_STREAMS)) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
}
Index: samba/source/smbd/reply.c
===================================================================
--- samba/source/smbd/reply.c.orig
+++ samba/source/smbd/reply.c
@@ -56,6 +56,7 @@ NTSTATUS check_path_syntax_internal(pstr
const char *s = srcname;
NTSTATUS ret = NT_STATUS_OK;
BOOL start_of_name_component = True;
+ BOOL stream_component = False;;
*p_last_component_contains_wcard = False;
@@ -122,10 +123,13 @@ NTSTATUS check_path_syntax_internal(pstr
if (!(*s & 0x80)) {
if (!posix_path) {
- if (*s <= 0x1f) {
+ if (!stream_component && *s <= 0x1f) {
return NT_STATUS_OBJECT_NAME_INVALID;
}
switch (*s) {
+ case ':':
+ stream_component = True;
+ break;
case '*':
case '?':
case '<':
@@ -1300,6 +1304,11 @@ int reply_open(connection_struct *conn,
return ERROR_NT(status);
}
+ if( is_ntfs_stream_name(fname)) {
+ END_PROFILE(SMBopen);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+
if (!map_open_params_to_ntcreate(fname, deny_mode, OPENX_FILE_EXISTS_OPEN,
&access_mask, &share_mode, &create_disposition, &create_options)) {
END_PROFILE(SMBopen);
@@ -1431,6 +1440,11 @@ int reply_open_and_X(connection_struct *
return ERROR_NT(status);
}
+ if (is_ntfs_stream_name(fname)) {
+ END_PROFILE(SMBopenX);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+
if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun,
&access_mask,
&share_mode,
Index: samba/source/smbd/statvfs.c
===================================================================
--- samba/source/smbd/statvfs.c.orig
+++ samba/source/smbd/statvfs.c
@@ -100,6 +100,11 @@ static int darwin_fs_capabilities(const
caps |= FILE_PERSISTENT_ACLS;
}
+ if (INTERFACE_CAP(vcaps, VOL_CAP_INT_NAMEDSTREAMS) &&
+ INTERFACE_CAP(vcaps, VOL_CAP_INT_EXTENDED_ATTR)) {
+ caps |= FILE_NAMED_STREAMS;
+ }
+
return caps;
}
@@ -140,12 +145,8 @@ int sys_statvfs(const char *path, vfs_st
#elif defined(DARWINOS)
return darwin_statvfs(path, statbuf);
#else
- /* BB change this to return invalid level */
-#ifdef EOPNOTSUPP
- return EOPNOTSUPP;
-#else
+ errno = ENOSYS;
return -1;
-#endif /* EOPNOTSUPP */
#endif /* LINUX */
}
Index: samba/source/smbd/trans2.c
===================================================================
--- samba/source/smbd/trans2.c.orig
+++ samba/source/smbd/trans2.c
@@ -2553,10 +2553,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAva
SBIG_UINT(pdata,40,svfs.FreeFileNodes);
SBIG_UINT(pdata,48,svfs.FsIdentifier);
DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
-#ifdef EOPNOTSUPP
- } else if (rc == EOPNOTSUPP) {
+ } else if (rc == -1 && errno == ENOSYS) {
return ERROR_NT(NT_STATUS_INVALID_LEVEL);
-#endif /* EOPNOTSUPP */
} else {
DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
return ERROR_DOS(ERRSRV,ERRerror);