Repository: conan-io/conan

Issue:
Conan fails download 
Conan fails download when given a package name of `"*/*@*/*" `

`conan download "*/*@*/*" -r repo`

`File "c:\python27\lib\site-packages\conans\client\command.py", line 1230, in run
    method(args[0][1:])
  File "c:\python27\lib\site-packages\conans\client\command.py", line 276, in download
    remote=args.remote, recipe=args.recipe)
  File "c:\python27\lib\site-packages\conans\client\conan_api.py", line 79, in wrapper
    return f(*args, **kwargs)
  File "c:\python27\lib\site-packages\conans\client\conan_api.py", line 403, in download
    self._client_cache, self._user_io.out, recorder)
  File "c:\python27\lib\site-packages\conans\client\cmd\download.py", line 20, in download
    remote_manager.get_recipe(reference, remote)
  File "c:\python27\lib\site-packages\conans\client\remote_manager.py", line 176, in get_recipe
    rmdir(dest_folder)
  File "c:\python27\lib\site-packages\conans\util\files.py", line 202, in rmdir
    shutil.rmtree(path, onerror=_change_permissions)
  File "c:\python27\lib\shutil.py", line 253, in rmtree
    onerror(os.listdir, path, sys.exc_info())
  File "c:\python27\lib\site-packages\conans\util\files.py", line 194, in _change_permissions
    os.chmod(path, stat.S_IWUSR)
WindowsError: [Error 123] The filename, directory name, or volume label syntax is incorrect: 'C:\\Users\\user\\.conan\\data\\*\\*\\*\\*\\export'`

I would expect it to either: 
Throw
`ERROR: Wrong package recipe reference *@*
Write something like OpenCV/1.0.6@user/stable`
or download the whole remote repo

OS: Windows 10
Conan version 1.6.1



Discussion:
Yes, certainly, this should throw an error, patterns are not used in ``conan download``.
Lets try to fix this, thanks for reporting!

Resolving patch:
diff --git a/conans/client/cmd/uploader.py b/conans/client/cmd/uploader.py
--- a/conans/client/cmd/uploader.py
+++ b/conans/client/cmd/uploader.py
@@ -2,21 +2,12 @@
 import time
 from conans.client.source import complete_recipe_sources
 from conans.errors import ConanException, NotFoundException
-from conans.model.ref import PackageReference, ConanFileReference
+from conans.model.ref import PackageReference, ConanFileReference, check_valid_ref
 from conans.search.search import search_recipes, search_packages
 from conans.util.files import load
 from conans.util.log import logger
 
 
-def _is_a_reference(ref):
-    try:
-        ConanFileReference.loads(ref)
-        return "*" not in ref  # If is a pattern, it is not a reference
-    except ConanException:
-        pass
-    return False
-
-
 UPLOAD_POLICY_FORCE = "force-upload"
 UPLOAD_POLICY_NO_OVERWRITE = "no-overwrite"
 UPLOAD_POLICY_NO_OVERWRITE_RECIPE = "no-overwrite-recipe"
@@ -38,11 +29,11 @@ def upload(self, recorder, reference_or_pattern, package_id=None, all_packages=N
                remote_name=None, query=None):
         """If package_id is provided, conan_reference_or_pattern is a ConanFileReference"""
 
-        if package_id and not _is_a_reference(reference_or_pattern):
+        if package_id and not check_valid_ref(reference_or_pattern, allow_pattern=False):
             raise ConanException("-p parameter only allowed with a valid recipe reference, "
                                  "not with a pattern")
         t1 = time.time()
-        if package_id or _is_a_reference(reference_or_pattern):  # Upload package
+        if package_id or check_valid_ref(reference_or_pattern, allow_pattern=False):  # Upload package
             ref = ConanFileReference.loads(reference_or_pattern)
             references = [ref, ]
             confirm = True
diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py
--- a/conans/client/conan_api.py
+++ b/conans/client/conan_api.py
@@ -29,7 +29,7 @@
 from conans.client.cmd.test import PackageTester
 from conans.client.userio import UserIO
 from conans.errors import ConanException
-from conans.model.ref import ConanFileReference, PackageReference
+from conans.model.ref import ConanFileReference, PackageReference, check_valid_ref
 from conans.model.version import Version
 from conans.paths import get_conan_user_home, CONANINFO, BUILD_INFO
 from conans.util.env_reader import get_env
@@ -433,10 +433,14 @@ def download(self, reference, remote_name=None, package=None, recipe=False):
             raise ConanException("recipe parameter cannot be used together with package")
         # Install packages without settings (fixed ids or all)
         conan_ref = ConanFileReference.loads(reference)
-        recorder = ActionRecorder()
-        download(conan_ref, package, remote_name, recipe, self._registry, self._remote_manager,
-                 self._client_cache, self._user_io.out, recorder, self._loader,
-                 self._plugin_manager)
+
+        if check_valid_ref(conan_ref, allow_pattern=False):
+            recorder = ActionRecorder()
+            download(conan_ref, package, remote_name, recipe, self._registry, self._remote_manager,
+                     self._client_cache, self._user_io.out, recorder, self._loader,
+                     self._plugin_manager)
+        else:
+            raise ConanException("Provide a valid full reference without wildcards.")
 
     @api_method
     def install_reference(self, reference, settings=None, options=None, env=None,
diff --git a/conans/model/ref.py b/conans/model/ref.py
--- a/conans/model/ref.py
+++ b/conans/model/ref.py
@@ -5,6 +5,16 @@
 from conans.model.version import Version
 
 
+def check_valid_ref(ref, allow_pattern):
+    try:
+        if not isinstance(ref, ConanFileReference):
+            ref = ConanFileReference.loads(ref, validate=True)
+        return "*" not in ref or allow_pattern
+    except ConanException:
+        pass
+    return False
+
+
 class ConanName(object):
     _max_chars = 51
     _min_chars = 2


Test patch:
diff --git a/conans/test/command/download_test.py b/conans/test/command/download_test.py
--- a/conans/test/command/download_test.py
+++ b/conans/test/command/download_test.py
@@ -153,3 +153,9 @@ class Pkg(ConanFile):
         error = client.run("download pkg/0.1@lasote/stable -p=wrong", ignore_error=True)
         self.assertTrue(error)
         self.assertIn("ERROR: Package binary 'pkg/0.1@lasote/stable:wrong' not found in 'default'", client.out)
+
+    def test_download_pattern(self):
+        client = TestClient()
+        error = client.run("download pkg/*@user/channel", ignore_error=True)
+        self.assertTrue(error)
+        self.assertIn("Provide a valid full reference without wildcards", client.out)
diff --git a/conans/test/model/ref_test.py b/conans/test/model/ref_test.py
--- a/conans/test/model/ref_test.py
+++ b/conans/test/model/ref_test.py
@@ -1,5 +1,5 @@
 import unittest
-from conans.model.ref import ConanFileReference, ConanName, InvalidNameException
+from conans.model.ref import ConanFileReference, ConanName, InvalidNameException, check_valid_ref
 from conans.errors import ConanException
 
 
@@ -93,3 +93,22 @@ def validate_name_version_test(self):
     def validate_name_version_test_invalid(self):
         self._check_invalid_format("[no.close.bracket", True)
         self._check_invalid_format("no.open.bracket]", True)
+
+
+class CheckValidRefTest(unittest.TestCase):
+
+    def test_string(self):
+        self.assertTrue(check_valid_ref("package/1.0@user/channel", allow_pattern=False))
+        self.assertTrue(check_valid_ref("package/1.0@user/channel", allow_pattern=True))
+
+        self.assertFalse(check_valid_ref("package/*@user/channel", allow_pattern=False))
+        self.assertTrue(check_valid_ref("package/1.0@user/channel", allow_pattern=True))
+
+    def test_conanfileref(self):
+        ref = ConanFileReference.loads("package/1.0@user/channel")
+        self.assertTrue(check_valid_ref(ref, allow_pattern=False))
+        self.assertTrue(check_valid_ref(ref, allow_pattern=True))
+
+        ref_pattern = ConanFileReference.loads("package/*@user/channel")
+        self.assertFalse(check_valid_ref(ref_pattern, allow_pattern=False))
+        self.assertTrue(check_valid_ref(ref_pattern, allow_pattern=True))