diff --git a/source3/include/libsmb_internal.h b/source3/include/libsmb_internal.h index 3b909d1..38c6d4b 100644 --- a/source3/include/libsmb_internal.h +++ b/source3/include/libsmb_internal.h @@ -151,6 +151,14 @@ struct SMBC_internal_data { bool full_time_names; /* + * Enable POSIX extensions before opening files/directories + * Will silently ignore if the server does not support the POSIX + * extensions + */ + + bool posix_extensions; + + /* * The share mode of a file being opened. To match POSIX semantics * (and maintain backward compatibility), DENY_NONE is the default. */ diff --git a/source3/include/libsmbclient.h b/source3/include/libsmbclient.h index a8b27b7..59fee70 100644 --- a/source3/include/libsmbclient.h +++ b/source3/include/libsmbclient.h @@ -694,7 +694,13 @@ smbc_getOptionNoAutoAnonymousLogin(SMBCCTX *c); void smbc_setOptionNoAutoAnonymousLogin(SMBCCTX *c, smbc_bool b); +/** Get whether to enable POSIX extensions if available */ +smbc_bool +smbc_getOptionPosixExtensions(SMBCCTX *c); +/** Set whether to enable POSIX extensions if available */ +void +smbc_setOptionPosixExtensions(SMBCCTX *c, smbc_bool b); /************************************* * Getters and setters for FUNCTIONS * diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c index 1984338..3bb7e36 100644 --- a/source3/libsmb/libsmb_context.c +++ b/source3/libsmb/libsmb_context.c @@ -72,6 +72,7 @@ smbc_new_context(void) smbc_setOptionBrowseMaxLmbCount(context, 3); /* # LMBs to query */ smbc_setOptionUrlEncodeReaddirEntries(context, False); smbc_setOptionOneSharePerServer(context, False); + smbc_setOptionPosixExtensions(context, True); smbc_setFunctionAuthData(context, SMBC_get_auth_data); smbc_setFunctionCheckServer(context, SMBC_check_server); diff --git a/source3/libsmb/libsmb_file.c b/source3/libsmb/libsmb_file.c index ece056d..0fe05c1 100644 --- a/source3/libsmb/libsmb_file.c +++ b/source3/libsmb/libsmb_file.c @@ -26,6 +26,97 @@ #include "libsmbclient.h" #include "libsmb_internal.h" +smbc_bool +SMBC_enable_posix(SMBCCTX *ctx, struct cli_state *cli) +{ + uint16 major, minor; + uint32 caplow, caphigh; + char *caps; + + if (!SERVER_HAS_UNIX_CIFS(cli)) { + d_printf("Server doesn't support UNIX CIFS extensions.\n"); + return 1; + } + + if (!cli_unix_extensions_version(cli, &major, &minor, &caplow, &caphigh)) { + d_printf("Can't get UNIX CIFS extensions version from server.\n"); + return 1; + } + + //d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor); + + caps = talloc_strdup(ctx, ""); + if (!caps) { + return 1; + } + if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) { + caps = talloc_asprintf_append(caps, "locks "); + if (!caps) { + return 1; + } + } + if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) { + caps = talloc_asprintf_append(caps, "acls "); + if (!caps) { + return 1; + } + } + if (caplow & CIFS_UNIX_XATTTR_CAP) { + caps = talloc_asprintf_append(caps, "eas "); + if (!caps) { + return 1; + } + } + if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) { + caps = talloc_asprintf_append(caps, "pathnames "); + if (!caps) { + return 1; + } + } + if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) { + caps = talloc_asprintf_append(caps, "posix_path_operations "); + if (!caps) { + return 1; + } + } + if (caplow & CIFS_UNIX_LARGE_READ_CAP) { + caps = talloc_asprintf_append(caps, "large_read "); + if (!caps) { + return 1; + } + } + if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) { + caps = talloc_asprintf_append(caps, "large_write "); + if (!caps) { + return 1; + } + } + if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) { + caps = talloc_asprintf_append(caps, "posix_encrypt "); + if (!caps) { + return 1; + } + } + if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) { + caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt "); + if (!caps) { + return 1; + } + } + + if (*caps && caps[strlen(caps)-1] == ' ') { + caps[strlen(caps)-1] = '\0'; + } + + //d_printf("Server supports CIFS capabilities %s\n", caps); + + if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) { + d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli)); + return 1; + } + + return 0; +} /* * Routine to open() a file ... @@ -123,6 +214,9 @@ SMBC_open_ctx(SMBCCTX *context, return NULL; } /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ + + if (context->internal->posix_extensions) + SMBC_enable_posix(context, targetcli); if ((fd = cli_open(targetcli, targetpath, flags, context->internal->share_mode)) < 0) { diff --git a/source3/libsmb/libsmb_setget.c b/source3/libsmb/libsmb_setget.c index d0823bd..c9a6bd5 100644 --- a/source3/libsmb/libsmb_setget.c +++ b/source3/libsmb/libsmb_setget.c @@ -385,6 +385,20 @@ smbc_setOptionNoAutoAnonymousLogin(SMBCCTX *c, smbc_bool b) } } +/** Get whether to enable POSIX extensions if available */ +smbc_bool +smbc_getOptionPosixExtensions(SMBCCTX *c) +{ + return c->internal->posix_extensions; +} + +/** Set whether to enable POSIX extensions if available */ +void +smbc_setOptionPosixExtensions(SMBCCTX *c, smbc_bool b) +{ + c->internal->posix_extensions = b; +} + /** Get the function for obtaining authentication data */ smbc_get_auth_data_fn smbc_getFunctionAuthData(SMBCCTX *c)