We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unlink simprocedure missing errno behavior
<!--
*Disclaimer:
The angr suite is maintained by a small team of volunteers.
While we cannot guarantee any timeliness for fixes and enhancements, we will do our best.
For more real-time help with angr, from us and the community, join our [Slack.](http://angr.io/invite/)*
-->

---

**Is your feature request related to a problem? Please describe.**
The unlink() function/syscall can set a diverse range of errno values. The simprocedure version of unlink doesn't model any of them, which causes incorrect execution of programs that use this interface.

The problem I'm specifically having is distinguishing failure because an existing file can't be removed, and failure because there is no file to remove.

**Describe the solution you would like.**
Add relevant errno assignments to the simprocedure.  I'm not sure if the simfs function gives enough data to decide which error to return on failure, so its return might need to be augmented, as well.

**Please include a sample of what *should* work if this feature is implemented.**
Currently, the marked branch in the following C code is unreachable:

```
int my_remove() {
   if(remove("/foo/bar")) {
      if(ERRNO == ENOENT) {
         //UNREACHABLE D:
         return 0
      }
      return 1
   }
   return 0
}
```

**Describe alternatives you have considered.**
Forcing the simfs remove() operation to succeed would make my problem go away, but it doesn't solve the general issue that code reading the errno values after a failure won't work properly.

**Additional context.**
<!--
Add any other context or screenshots about the feature request here.
-->


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `angr/procedures/linux_kernel/unlink.py`
Content:
```
1 import angr
2 
3 ######################################
4 # unlink
5 ######################################
6 
7 class unlink(angr.SimProcedure): #pylint:disable=W0622
8     #pylint:disable=arguments-differ
9 
10     def run(self, path_addr):
11         # This is a dummy for now
12         strlen = angr.SIM_PROCEDURES['libc']['strlen']
13 
14         p_strlen = self.inline_call(strlen, path_addr)
15         str_expr = self.state.memory.load(path_addr, p_strlen.max_null_index, endness='Iend_BE')
16         str_val = self.state.solver.eval(str_expr, cast_to=bytes)
17 
18         if self.state.fs.delete(str_val):
19             return 0
20         else:
21             return -1
22
```
--- 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/angr/procedures/linux_kernel/unlink.py b/angr/procedures/linux_kernel/unlink.py
--- a/angr/procedures/linux_kernel/unlink.py
+++ b/angr/procedures/linux_kernel/unlink.py
@@ -15,6 +15,10 @@
         str_expr = self.state.memory.load(path_addr, p_strlen.max_null_index, endness='Iend_BE')
         str_val = self.state.solver.eval(str_expr, cast_to=bytes)
 
+        # Check if entity exists before attempting to unlink
+        if not self.state.fs.get(str_val):
+            return self.state.libc.ret_errno('ENOENT')
+
         if self.state.fs.delete(str_val):
             return 0
         else:

{"golden_diff": "diff --git a/angr/procedures/linux_kernel/unlink.py b/angr/procedures/linux_kernel/unlink.py\n--- a/angr/procedures/linux_kernel/unlink.py\n+++ b/angr/procedures/linux_kernel/unlink.py\n@@ -15,6 +15,10 @@\n         str_expr = self.state.memory.load(path_addr, p_strlen.max_null_index, endness='Iend_BE')\n         str_val = self.state.solver.eval(str_expr, cast_to=bytes)\n \n+        # Check if entity exists before attempting to unlink\n+        if not self.state.fs.get(str_val):\n+            return self.state.libc.ret_errno('ENOENT')\n+\n         if self.state.fs.delete(str_val):\n             return 0\n         else:\n", "issue": "Unlink simprocedure missing errno behavior\n<!--\r\n*Disclaimer:\r\nThe angr suite is maintained by a small team of volunteers.\r\nWhile we cannot guarantee any timeliness for fixes and enhancements, we will do our best.\r\nFor more real-time help with angr, from us and the community, join our [Slack.](http://angr.io/invite/)*\r\n-->\r\n\r\n---\r\n\r\n**Is your feature request related to a problem? Please describe.**\r\nThe unlink() function/syscall can set a diverse range of errno values. The simprocedure version of unlink doesn't model any of them, which causes incorrect execution of programs that use this interface.\r\n\r\nThe problem I'm specifically having is distinguishing failure because an existing file can't be removed, and failure because there is no file to remove.\r\n\r\n**Describe the solution you would like.**\r\nAdd relevant errno assignments to the simprocedure.  I'm not sure if the simfs function gives enough data to decide which error to return on failure, so its return might need to be augmented, as well.\r\n\r\n**Please include a sample of what *should* work if this feature is implemented.**\r\nCurrently, the marked branch in the following C code is unreachable:\r\n\r\n```\r\nint my_remove() {\r\n   if(remove(\"/foo/bar\")) {\r\n      if(ERRNO == ENOENT) {\r\n         //UNREACHABLE D:\r\n         return 0\r\n      }\r\n      return 1\r\n   }\r\n   return 0\r\n}\r\n```\r\n\r\n**Describe alternatives you have considered.**\r\nForcing the simfs remove() operation to succeed would make my problem go away, but it doesn't solve the general issue that code reading the errno values after a failure won't work properly.\r\n\r\n**Additional context.**\r\n<!--\r\nAdd any other context or screenshots about the feature request here.\r\n-->\r\n\n", "before_files": [{"content": "import angr\n\n######################################\n# unlink\n######################################\n\nclass unlink(angr.SimProcedure): #pylint:disable=W0622\n    #pylint:disable=arguments-differ\n\n    def run(self, path_addr):\n        # This is a dummy for now\n        strlen = angr.SIM_PROCEDURES['libc']['strlen']\n\n        p_strlen = self.inline_call(strlen, path_addr)\n        str_expr = self.state.memory.load(path_addr, p_strlen.max_null_index, endness='Iend_BE')\n        str_val = self.state.solver.eval(str_expr, cast_to=bytes)\n\n        if self.state.fs.delete(str_val):\n            return 0\n        else:\n            return -1\n", "path": "angr/procedures/linux_kernel/unlink.py"}], "after_files": [{"content": "import angr\n\n######################################\n# unlink\n######################################\n\nclass unlink(angr.SimProcedure): #pylint:disable=W0622\n    #pylint:disable=arguments-differ\n\n    def run(self, path_addr):\n        # This is a dummy for now\n        strlen = angr.SIM_PROCEDURES['libc']['strlen']\n\n        p_strlen = self.inline_call(strlen, path_addr)\n        str_expr = self.state.memory.load(path_addr, p_strlen.max_null_index, endness='Iend_BE')\n        str_val = self.state.solver.eval(str_expr, cast_to=bytes)\n\n        # Check if entity exists before attempting to unlink\n        if not self.state.fs.get(str_val):\n            return self.state.libc.ret_errno('ENOENT')\n\n        if self.state.fs.delete(str_val):\n            return 0\n        else:\n            return -1\n", "path": "angr/procedures/linux_kernel/unlink.py"}]}