We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Better handling of posix replica URLs
Motivation
----------

With `rucio.rse.protocols.posix.Default` implementation, the replicas with "file" schema always have port `0` in them, eg

`TEST1: file://:0/tmp/testfile`

Modification
------------

Override `lfns2pfns()` in the posix protocol.

I will submit a pull request for this shortly.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/rucio/rse/protocols/posix.py`
Content:
```
1 # Copyright European Organization for Nuclear Research (CERN)
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # You may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 # http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Authors:
9 # - Ralph Vigne, <ralph.vigne@cern.ch>, 2012-2014
10 # - Nicolo Magini, <nicolo.magini@cern.ch>, 2018
11 #
12 # PY3K COMPATIBLE
13 
14 import os
15 import os.path
16 import shutil
17 from subprocess import call
18 
19 from rucio.common import exception
20 from rucio.common.utils import adler32
21 from rucio.rse.protocols import protocol
22 
23 
24 class Default(protocol.RSEProtocol):
25     """ Implementing access to RSEs using the local filesystem."""
26 
27     def exists(self, pfn):
28         """
29             Checks if the requested file is known by the referred RSE.
30 
31             :param pfn: Physical file name
32 
33             :returns: True if the file exists, False if it doesn't
34 
35             :raises SourceNotFound: if the source file was not found on the referred storage.
36         """
37         status = ''
38         try:
39             status = os.path.exists(self.pfn2path(pfn))
40         except Exception as e:
41             raise exception.ServiceUnavailable(e)
42         return status
43 
44     def connect(self):
45         """
46             Establishes the actual connection to the referred RSE.
47 
48             :param: credentials needed to establish a connection with the stroage.
49 
50             :raises RSEAccessDenied: if no connection could be established.
51         """
52         pass
53 
54     def close(self):
55         """ Closes the connection to RSE."""
56         pass
57 
58     def get(self, pfn, dest, transfer_timeout=None):
59         """ Provides access to files stored inside connected the RSE.
60 
61             :param pfn: Physical file name of requested file
62             :param dest: Name and path of the files when stored at the client
63             :param transfer_timeout Transfer timeout (in seconds) - dummy
64 
65             :raises DestinationNotAccessible: if the destination storage was not accessible.
66             :raises ServiceUnavailable: if some generic error occured in the library.
67             :raises SourceNotFound: if the source file was not found on the referred storage.
68          """
69         try:
70             shutil.copy(self.pfn2path(pfn), dest)
71         except IOError as e:
72             try:  # To check if the error happend local or remote
73                 with open(dest, 'wb'):
74                     pass
75                 call(['rm', '-rf', dest])
76             except IOError as e:
77                 if e.errno == 2:
78                     raise exception.DestinationNotAccessible(e)
79                 else:
80                     raise exception.ServiceUnavailable(e)
81             if e.errno == 2:
82                 raise exception.SourceNotFound(e)
83             else:
84                 raise exception.ServiceUnavailable(e)
85 
86     def put(self, source, target, source_dir=None, transfer_timeout=None):
87         """
88             Allows to store files inside the referred RSE.
89 
90             :param source: path to the source file on the client file system
91             :param target: path to the destination file on the storage
92             :param source_dir: Path where the to be transferred files are stored in the local file system
93             :param transfer_timeout Transfer timeout (in seconds) - dummy
94 
95             :raises DestinationNotAccessible: if the destination storage was not accessible.
96             :raises ServiceUnavailable: if some generic error occured in the library.
97             :raises SourceNotFound: if the source file was not found on the referred storage.
98         """
99         target = self.pfn2path(target)
100 
101         if source_dir:
102             sf = source_dir + '/' + source
103         else:
104             sf = source
105         try:
106             dirs = os.path.dirname(target)
107             if not os.path.exists(dirs):
108                 os.makedirs(dirs)
109             shutil.copy(sf, target)
110         except IOError as e:
111             if e.errno == 2:
112                 raise exception.SourceNotFound(e)
113             elif not self.exists(self.rse['prefix']):
114                 path = ''
115                 for p in self.rse['prefix'].split('/'):
116                     path += p + '/'
117                     os.mkdir(path)
118                 shutil.copy(sf, self.pfn2path(target))
119             else:
120                 raise exception.DestinationNotAccessible(e)
121 
122     def delete(self, pfn):
123         """ Deletes a file from the connected RSE.
124 
125             :param pfn: pfn to the to be deleted file
126 
127             :raises ServiceUnavailable: if some generic error occured in the library.
128             :raises SourceNotFound: if the source file was not found on the referred storage.
129         """
130         try:
131             os.remove(self.pfn2path(pfn))
132         except OSError as e:
133             if e.errno == 2:
134                 raise exception.SourceNotFound(e)
135 
136     def rename(self, pfn, new_pfn):
137         """ Allows to rename a file stored inside the connected RSE.
138 
139             :param path: path to the current file on the storage
140             :param new_path: path to the new file on the storage
141 
142             :raises DestinationNotAccessible: if the destination storage was not accessible.
143             :raises ServiceUnavailable: if some generic error occured in the library.
144             :raises SourceNotFound: if the source file was not found on the referred storage.
145         """
146         path = self.pfn2path(pfn)
147         new_path = self.pfn2path(new_pfn)
148         try:
149             if not os.path.exists(os.path.dirname(new_path)):
150                 os.makedirs(os.path.dirname(new_path))
151             os.rename(path, new_path)
152         except IOError as e:
153             if e.errno == 2:
154                 if self.exists(self.pfn2path(path)):
155                     raise exception.SourceNotFound(e)
156                 else:
157                     raise exception.DestinationNotAccessible(e)
158             else:
159                 raise exception.ServiceUnavailable(e)
160 
161     def pfn2path(self, pfn):
162         tmp = list(self.parse_pfns(pfn).values())[0]
163         return '/'.join([tmp['prefix'], tmp['path'], tmp['name']])
164 
165     def stat(self, pfn):
166         """ Determines the file size in bytes and checksum (adler32) of the provided file.
167 
168             :param pfn: The PFN the file.
169 
170             :returns: a dict containing the keys filesize and adler32.
171         """
172         path = self.pfn2path(pfn)
173         return {'filesize': os.stat(path)[os.path.stat.ST_SIZE], 'adler32': adler32(path)}
174
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/rucio/rse/protocols/posix.py b/lib/rucio/rse/protocols/posix.py
--- a/lib/rucio/rse/protocols/posix.py
+++ b/lib/rucio/rse/protocols/posix.py
@@ -8,6 +8,7 @@
 # Authors:
 # - Ralph Vigne, <ralph.vigne@cern.ch>, 2012-2014
 # - Nicolo Magini, <nicolo.magini@cern.ch>, 2018
+# - David Cameron, <david.cameron@cern.ch>, 2020
 #
 # PY3K COMPATIBLE
 
@@ -158,6 +159,43 @@
             else:
                 raise exception.ServiceUnavailable(e)
 
+    def lfns2pfns(self, lfns):
+        """ Returns fully qualified PFNs for the file referred by each lfn in
+            the lfns list.
+
+            :param lfns: List of lfns. If lfn['path'] is present it is used as
+                   the path to the file, otherwise the path is constructed
+                   deterministically.
+
+            :returns: Fully qualified PFNs.
+        """
+        pfns = {}
+        prefix = self.attributes['prefix']
+
+        if not prefix.startswith('/'):
+            prefix = ''.join(['/', prefix])
+        if not prefix.endswith('/'):
+            prefix = ''.join([prefix, '/'])
+
+        lfns = [lfns] if isinstance(lfns, dict) else lfns
+        for lfn in lfns:
+            scope, name = str(lfn['scope']), lfn['name']
+            if lfn.get('path'):
+                pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],
+                                                         '://',
+                                                         self.attributes['hostname'],
+                                                         prefix,
+                                                         lfn['path'] if not lfn['path'].startswith('/') else lfn['path'][1:]
+                                                         ])
+            else:
+                pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],
+                                                         '://',
+                                                         self.attributes['hostname'],
+                                                         prefix,
+                                                         self._get_path(scope=scope, name=name)
+                                                         ])
+        return pfns
+
     def pfn2path(self, pfn):
         tmp = list(self.parse_pfns(pfn).values())[0]
         return '/'.join([tmp['prefix'], tmp['path'], tmp['name']])

{"golden_diff": "diff --git a/lib/rucio/rse/protocols/posix.py b/lib/rucio/rse/protocols/posix.py\n--- a/lib/rucio/rse/protocols/posix.py\n+++ b/lib/rucio/rse/protocols/posix.py\n@@ -8,6 +8,7 @@\n # Authors:\n # - Ralph Vigne, <ralph.vigne@cern.ch>, 2012-2014\n # - Nicolo Magini, <nicolo.magini@cern.ch>, 2018\n+# - David Cameron, <david.cameron@cern.ch>, 2020\n #\n # PY3K COMPATIBLE\n \n@@ -158,6 +159,43 @@\n             else:\n                 raise exception.ServiceUnavailable(e)\n \n+    def lfns2pfns(self, lfns):\n+        \"\"\" Returns fully qualified PFNs for the file referred by each lfn in\n+            the lfns list.\n+\n+            :param lfns: List of lfns. If lfn['path'] is present it is used as\n+                   the path to the file, otherwise the path is constructed\n+                   deterministically.\n+\n+            :returns: Fully qualified PFNs.\n+        \"\"\"\n+        pfns = {}\n+        prefix = self.attributes['prefix']\n+\n+        if not prefix.startswith('/'):\n+            prefix = ''.join(['/', prefix])\n+        if not prefix.endswith('/'):\n+            prefix = ''.join([prefix, '/'])\n+\n+        lfns = [lfns] if isinstance(lfns, dict) else lfns\n+        for lfn in lfns:\n+            scope, name = str(lfn['scope']), lfn['name']\n+            if lfn.get('path'):\n+                pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],\n+                                                         '://',\n+                                                         self.attributes['hostname'],\n+                                                         prefix,\n+                                                         lfn['path'] if not lfn['path'].startswith('/') else lfn['path'][1:]\n+                                                         ])\n+            else:\n+                pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],\n+                                                         '://',\n+                                                         self.attributes['hostname'],\n+                                                         prefix,\n+                                                         self._get_path(scope=scope, name=name)\n+                                                         ])\n+        return pfns\n+\n     def pfn2path(self, pfn):\n         tmp = list(self.parse_pfns(pfn).values())[0]\n         return '/'.join([tmp['prefix'], tmp['path'], tmp['name']])\n", "issue": "Better handling of posix replica URLs\nMotivation\r\n----------\r\n\r\nWith `rucio.rse.protocols.posix.Default` implementation, the replicas with \"file\" schema always have port `0` in them, eg\r\n\r\n`TEST1: file://:0/tmp/testfile`\r\n\r\nModification\r\n------------\r\n\r\nOverride `lfns2pfns()` in the posix protocol.\r\n\r\nI will submit a pull request for this shortly.\r\n\n", "before_files": [{"content": "# Copyright European Organization for Nuclear Research (CERN)\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# You may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Authors:\n# - Ralph Vigne, <ralph.vigne@cern.ch>, 2012-2014\n# - Nicolo Magini, <nicolo.magini@cern.ch>, 2018\n#\n# PY3K COMPATIBLE\n\nimport os\nimport os.path\nimport shutil\nfrom subprocess import call\n\nfrom rucio.common import exception\nfrom rucio.common.utils import adler32\nfrom rucio.rse.protocols import protocol\n\n\nclass Default(protocol.RSEProtocol):\n    \"\"\" Implementing access to RSEs using the local filesystem.\"\"\"\n\n    def exists(self, pfn):\n        \"\"\"\n            Checks if the requested file is known by the referred RSE.\n\n            :param pfn: Physical file name\n\n            :returns: True if the file exists, False if it doesn't\n\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n        \"\"\"\n        status = ''\n        try:\n            status = os.path.exists(self.pfn2path(pfn))\n        except Exception as e:\n            raise exception.ServiceUnavailable(e)\n        return status\n\n    def connect(self):\n        \"\"\"\n            Establishes the actual connection to the referred RSE.\n\n            :param: credentials needed to establish a connection with the stroage.\n\n            :raises RSEAccessDenied: if no connection could be established.\n        \"\"\"\n        pass\n\n    def close(self):\n        \"\"\" Closes the connection to RSE.\"\"\"\n        pass\n\n    def get(self, pfn, dest, transfer_timeout=None):\n        \"\"\" Provides access to files stored inside connected the RSE.\n\n            :param pfn: Physical file name of requested file\n            :param dest: Name and path of the files when stored at the client\n            :param transfer_timeout Transfer timeout (in seconds) - dummy\n\n            :raises DestinationNotAccessible: if the destination storage was not accessible.\n            :raises ServiceUnavailable: if some generic error occured in the library.\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n         \"\"\"\n        try:\n            shutil.copy(self.pfn2path(pfn), dest)\n        except IOError as e:\n            try:  # To check if the error happend local or remote\n                with open(dest, 'wb'):\n                    pass\n                call(['rm', '-rf', dest])\n            except IOError as e:\n                if e.errno == 2:\n                    raise exception.DestinationNotAccessible(e)\n                else:\n                    raise exception.ServiceUnavailable(e)\n            if e.errno == 2:\n                raise exception.SourceNotFound(e)\n            else:\n                raise exception.ServiceUnavailable(e)\n\n    def put(self, source, target, source_dir=None, transfer_timeout=None):\n        \"\"\"\n            Allows to store files inside the referred RSE.\n\n            :param source: path to the source file on the client file system\n            :param target: path to the destination file on the storage\n            :param source_dir: Path where the to be transferred files are stored in the local file system\n            :param transfer_timeout Transfer timeout (in seconds) - dummy\n\n            :raises DestinationNotAccessible: if the destination storage was not accessible.\n            :raises ServiceUnavailable: if some generic error occured in the library.\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n        \"\"\"\n        target = self.pfn2path(target)\n\n        if source_dir:\n            sf = source_dir + '/' + source\n        else:\n            sf = source\n        try:\n            dirs = os.path.dirname(target)\n            if not os.path.exists(dirs):\n                os.makedirs(dirs)\n            shutil.copy(sf, target)\n        except IOError as e:\n            if e.errno == 2:\n                raise exception.SourceNotFound(e)\n            elif not self.exists(self.rse['prefix']):\n                path = ''\n                for p in self.rse['prefix'].split('/'):\n                    path += p + '/'\n                    os.mkdir(path)\n                shutil.copy(sf, self.pfn2path(target))\n            else:\n                raise exception.DestinationNotAccessible(e)\n\n    def delete(self, pfn):\n        \"\"\" Deletes a file from the connected RSE.\n\n            :param pfn: pfn to the to be deleted file\n\n            :raises ServiceUnavailable: if some generic error occured in the library.\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n        \"\"\"\n        try:\n            os.remove(self.pfn2path(pfn))\n        except OSError as e:\n            if e.errno == 2:\n                raise exception.SourceNotFound(e)\n\n    def rename(self, pfn, new_pfn):\n        \"\"\" Allows to rename a file stored inside the connected RSE.\n\n            :param path: path to the current file on the storage\n            :param new_path: path to the new file on the storage\n\n            :raises DestinationNotAccessible: if the destination storage was not accessible.\n            :raises ServiceUnavailable: if some generic error occured in the library.\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n        \"\"\"\n        path = self.pfn2path(pfn)\n        new_path = self.pfn2path(new_pfn)\n        try:\n            if not os.path.exists(os.path.dirname(new_path)):\n                os.makedirs(os.path.dirname(new_path))\n            os.rename(path, new_path)\n        except IOError as e:\n            if e.errno == 2:\n                if self.exists(self.pfn2path(path)):\n                    raise exception.SourceNotFound(e)\n                else:\n                    raise exception.DestinationNotAccessible(e)\n            else:\n                raise exception.ServiceUnavailable(e)\n\n    def pfn2path(self, pfn):\n        tmp = list(self.parse_pfns(pfn).values())[0]\n        return '/'.join([tmp['prefix'], tmp['path'], tmp['name']])\n\n    def stat(self, pfn):\n        \"\"\" Determines the file size in bytes and checksum (adler32) of the provided file.\n\n            :param pfn: The PFN the file.\n\n            :returns: a dict containing the keys filesize and adler32.\n        \"\"\"\n        path = self.pfn2path(pfn)\n        return {'filesize': os.stat(path)[os.path.stat.ST_SIZE], 'adler32': adler32(path)}\n", "path": "lib/rucio/rse/protocols/posix.py"}], "after_files": [{"content": "# Copyright European Organization for Nuclear Research (CERN)\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# You may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Authors:\n# - Ralph Vigne, <ralph.vigne@cern.ch>, 2012-2014\n# - Nicolo Magini, <nicolo.magini@cern.ch>, 2018\n# - David Cameron, <david.cameron@cern.ch>, 2020\n#\n# PY3K COMPATIBLE\n\nimport os\nimport os.path\nimport shutil\nfrom subprocess import call\n\nfrom rucio.common import exception\nfrom rucio.common.utils import adler32\nfrom rucio.rse.protocols import protocol\n\n\nclass Default(protocol.RSEProtocol):\n    \"\"\" Implementing access to RSEs using the local filesystem.\"\"\"\n\n    def exists(self, pfn):\n        \"\"\"\n            Checks if the requested file is known by the referred RSE.\n\n            :param pfn: Physical file name\n\n            :returns: True if the file exists, False if it doesn't\n\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n        \"\"\"\n        status = ''\n        try:\n            status = os.path.exists(self.pfn2path(pfn))\n        except Exception as e:\n            raise exception.ServiceUnavailable(e)\n        return status\n\n    def connect(self):\n        \"\"\"\n            Establishes the actual connection to the referred RSE.\n\n            :param: credentials needed to establish a connection with the stroage.\n\n            :raises RSEAccessDenied: if no connection could be established.\n        \"\"\"\n        pass\n\n    def close(self):\n        \"\"\" Closes the connection to RSE.\"\"\"\n        pass\n\n    def get(self, pfn, dest, transfer_timeout=None):\n        \"\"\" Provides access to files stored inside connected the RSE.\n\n            :param pfn: Physical file name of requested file\n            :param dest: Name and path of the files when stored at the client\n            :param transfer_timeout Transfer timeout (in seconds) - dummy\n\n            :raises DestinationNotAccessible: if the destination storage was not accessible.\n            :raises ServiceUnavailable: if some generic error occured in the library.\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n         \"\"\"\n        try:\n            shutil.copy(self.pfn2path(pfn), dest)\n        except IOError as e:\n            try:  # To check if the error happend local or remote\n                with open(dest, 'wb'):\n                    pass\n                call(['rm', '-rf', dest])\n            except IOError as e:\n                if e.errno == 2:\n                    raise exception.DestinationNotAccessible(e)\n                else:\n                    raise exception.ServiceUnavailable(e)\n            if e.errno == 2:\n                raise exception.SourceNotFound(e)\n            else:\n                raise exception.ServiceUnavailable(e)\n\n    def put(self, source, target, source_dir=None, transfer_timeout=None):\n        \"\"\"\n            Allows to store files inside the referred RSE.\n\n            :param source: path to the source file on the client file system\n            :param target: path to the destination file on the storage\n            :param source_dir: Path where the to be transferred files are stored in the local file system\n            :param transfer_timeout Transfer timeout (in seconds) - dummy\n\n            :raises DestinationNotAccessible: if the destination storage was not accessible.\n            :raises ServiceUnavailable: if some generic error occured in the library.\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n        \"\"\"\n        target = self.pfn2path(target)\n\n        if source_dir:\n            sf = source_dir + '/' + source\n        else:\n            sf = source\n        try:\n            dirs = os.path.dirname(target)\n            if not os.path.exists(dirs):\n                os.makedirs(dirs)\n            shutil.copy(sf, target)\n        except IOError as e:\n            if e.errno == 2:\n                raise exception.SourceNotFound(e)\n            elif not self.exists(self.rse['prefix']):\n                path = ''\n                for p in self.rse['prefix'].split('/'):\n                    path += p + '/'\n                    os.mkdir(path)\n                shutil.copy(sf, self.pfn2path(target))\n            else:\n                raise exception.DestinationNotAccessible(e)\n\n    def delete(self, pfn):\n        \"\"\" Deletes a file from the connected RSE.\n\n            :param pfn: pfn to the to be deleted file\n\n            :raises ServiceUnavailable: if some generic error occured in the library.\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n        \"\"\"\n        try:\n            os.remove(self.pfn2path(pfn))\n        except OSError as e:\n            if e.errno == 2:\n                raise exception.SourceNotFound(e)\n\n    def rename(self, pfn, new_pfn):\n        \"\"\" Allows to rename a file stored inside the connected RSE.\n\n            :param path: path to the current file on the storage\n            :param new_path: path to the new file on the storage\n\n            :raises DestinationNotAccessible: if the destination storage was not accessible.\n            :raises ServiceUnavailable: if some generic error occured in the library.\n            :raises SourceNotFound: if the source file was not found on the referred storage.\n        \"\"\"\n        path = self.pfn2path(pfn)\n        new_path = self.pfn2path(new_pfn)\n        try:\n            if not os.path.exists(os.path.dirname(new_path)):\n                os.makedirs(os.path.dirname(new_path))\n            os.rename(path, new_path)\n        except IOError as e:\n            if e.errno == 2:\n                if self.exists(self.pfn2path(path)):\n                    raise exception.SourceNotFound(e)\n                else:\n                    raise exception.DestinationNotAccessible(e)\n            else:\n                raise exception.ServiceUnavailable(e)\n\n    def lfns2pfns(self, lfns):\n        \"\"\" Returns fully qualified PFNs for the file referred by each lfn in\n            the lfns list.\n\n            :param lfns: List of lfns. If lfn['path'] is present it is used as\n                   the path to the file, otherwise the path is constructed\n                   deterministically.\n\n            :returns: Fully qualified PFNs.\n        \"\"\"\n        pfns = {}\n        prefix = self.attributes['prefix']\n\n        if not prefix.startswith('/'):\n            prefix = ''.join(['/', prefix])\n        if not prefix.endswith('/'):\n            prefix = ''.join([prefix, '/'])\n\n        lfns = [lfns] if isinstance(lfns, dict) else lfns\n        for lfn in lfns:\n            scope, name = str(lfn['scope']), lfn['name']\n            if lfn.get('path'):\n                pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],\n                                                         '://',\n                                                         self.attributes['hostname'],\n                                                         prefix,\n                                                         lfn['path'] if not lfn['path'].startswith('/') else lfn['path'][1:]\n                                                         ])\n            else:\n                pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],\n                                                         '://',\n                                                         self.attributes['hostname'],\n                                                         prefix,\n                                                         self._get_path(scope=scope, name=name)\n                                                         ])\n        return pfns\n\n    def pfn2path(self, pfn):\n        tmp = list(self.parse_pfns(pfn).values())[0]\n        return '/'.join([tmp['prefix'], tmp['path'], tmp['name']])\n\n    def stat(self, pfn):\n        \"\"\" Determines the file size in bytes and checksum (adler32) of the provided file.\n\n            :param pfn: The PFN the file.\n\n            :returns: a dict containing the keys filesize and adler32.\n        \"\"\"\n        path = self.pfn2path(pfn)\n        return {'filesize': os.stat(path)[os.path.stat.ST_SIZE], 'adler32': adler32(path)}\n", "path": "lib/rucio/rse/protocols/posix.py"}]}