all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
blob 211e0a4f4ca56abf71040f52972bfd2677947849 7711 bytes (raw)
name: gnu/packages/patches/guile-openat-and-friends-02.patch 	 # note: path name is non-authoritative(*)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
 
Guix-Upstream: https://lists.gnu.org/archive/html/guile-devel/2021-11/msg00005.html
From: Maxime Devos <maximedevos@telenet.be>
Subject: [PATCH v2 02/14]
 =?UTF-8?q?Allow=20file=20ports=20in=20=E2=80=98r?=
 =?UTF-8?q?eadlink=E2=80=99.?=
Date: Tue, 16 Nov 2021 11:06:25 +0000
Message-Id: <20211116110637.125579-3-maximedevos@telenet.be>
In-Reply-To: <20211116110637.125579-1-maximedevos@telenet.be>
References: <175c3a6572e832d84927937b309a3095cadf5702.camel@telenet.be>
 <20211116110637.125579-1-maximedevos@telenet.be>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* configure.ac: Detect whether ‘readlinkat’ is defined.
* libguile/filesys.c (scm_readlink): Support file ports
  when ‘readlinkat’ exists.
  (scm_init_filesys): Provide ‘chdir-ports’ when it exists.
* doc/ref/posix.texi (File System): Document it.
* test-suite/tests/filesys.test ("readlink"): Test it.
---
 configure.ac                  |  2 +-
 doc/ref/posix.texi            |  9 ++++--
 libguile/filesys.c            | 52 +++++++++++++++++++++++------
 test-suite/tests/filesys.test | 61 +++++++++++++++++++++++++++++++++++
 4 files changed, 112 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index b7e4663f7..4888f880d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -484,7 +484,7 @@ AC_CHECK_HEADERS([assert.h crt_externs.h])
 #   sendfile - non-POSIX, found in glibc
 #
 AC_CHECK_FUNCS([DINFINITY DQNAN cexp chsize clog clog10 ctermid         \
-  fesetround ftime ftruncate fchown fchmod fchdir			\
+  fesetround ftime ftruncate fchown fchmod fchdir readlinkat		\
   getcwd geteuid getsid							\
   gettimeofday getuid getgid gmtime_r ioctl lstat mkdir mkdtemp mknod   \
   nice readlink rename rmdir setegid seteuid                            \
diff --git a/doc/ref/posix.texi b/doc/ref/posix.texi
index 7555f9319..cd23240c4 100644
--- a/doc/ref/posix.texi
+++ b/doc/ref/posix.texi
@@ -757,8 +757,13 @@ file it points to.  @var{path} must be a string.
 
 @deffn {Scheme Procedure} readlink path
 @deffnx {C Function} scm_readlink (path)
-Return the value of the symbolic link named by @var{path} (a
-string), i.e., the file that the link points to.
+Return the value of the symbolic link named by @var{path} (a string, or
+a port if supported by the system), i.e., the file that the link points
+to.
+
+To read a symbolic link represented by a port, the symbolic link must
+have been opened with the @code{O_NOFOLLOW} and @code{O_PATH} flags.
+@code{(provided? 'readlink-port)} reports whether ports are supported.
 @end deffn
 
 @findex fchown
diff --git a/libguile/filesys.c b/libguile/filesys.c
index 2a9c36a12..c5bedec07 100644
--- a/libguile/filesys.c
+++ b/libguile/filesys.c
@@ -1045,10 +1045,30 @@ SCM_DEFINE (scm_symlink, "symlink", 2, 0, 0,
 #undef FUNC_NAME
 #endif /* HAVE_SYMLINK */
 
-SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0, 
+/* Static helper function for choosing between readlink
+   and readlinkat. */
+static int
+do_readlink (int fd, const char *c_path, char *buf, size_t size)
+{
+#ifdef HAVE_READLINKAT
+  if (fd != -1)
+    return readlinkat (fd, c_path, buf, size);
+#else
+  (void) fd;
+#endif
+  return readlink (c_path, buf, size);
+}
+
+SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0,
             (SCM path),
-	    "Return the value of the symbolic link named by @var{path} (a\n"
-	    "string), i.e., the file that the link points to.")
+            "Return the value of the symbolic link named by @var{path} (a\n"
+            "string, or a port if supported by the system),\n"
+            "i.e., the file that the link points to.\n"
+            "To read a symbolic link represented by a port, the symbolic\n"
+            "link must have been opened with the @code{O_NOFOLLOW} and\n"
+            "@code{O_PATH} flags."
+            "@code{(provided? 'readlink-port)} reports whether ports are\n"
+            "supported.")
 #define FUNC_NAME s_scm_readlink
 {
   int rv;
@@ -1056,20 +1076,31 @@ SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0,
   char *buf;
   SCM result;
   char *c_path;
-  
-  scm_dynwind_begin (0);
-
-  c_path = scm_to_locale_string (path);
-  scm_dynwind_free (c_path);
+  int fdes;
 
+  scm_dynwind_begin (0);
+#ifdef HAVE_READLINKAT
+  if (SCM_OPFPORTP (path))
+    {
+      c_path = "";
+      fdes = SCM_FPORT_FDES (path);
+    }
+  else
+#endif
+    {
+      fdes = -1;
+      c_path = scm_to_locale_string (path);
+      scm_dynwind_free (c_path);
+    }
   buf = scm_malloc (size);
 
-  while ((rv = readlink (c_path, buf, size)) == size)
+  while ((rv = do_readlink (fdes, c_path, buf, size)) == size)
     {
       free (buf);
       size *= 2;
       buf = scm_malloc (size);
     }
+  scm_remember_upto_here_1 (path);
   if (rv == -1)
     {
       int save_errno = errno;
@@ -2086,6 +2117,9 @@ scm_init_filesys ()
 #ifdef HAVE_FCHDIR
   scm_add_feature("chdir-port");
 #endif
+#ifdef HAVE_READLINKAT
+  scm_add_feature("readlink-port");
+#endif
 
 #include "filesys.x"
 }
diff --git a/test-suite/tests/filesys.test b/test-suite/tests/filesys.test
index 6b09a2ba0..7feb3492f 100644
--- a/test-suite/tests/filesys.test
+++ b/test-suite/tests/filesys.test
@@ -306,3 +306,64 @@
 
   (pass-if-exception "non-file port" exception:wrong-type-arg
     (chdir (open-input-string ""))))
+
+(with-test-prefix "readlink"
+  (false-if-exception (delete-file (test-symlink)))
+  (false-if-exception (delete-file (test-file)))
+  (call-with-output-file (test-file)
+    (lambda (port)
+      (display "hello" port)))
+  (if (not (false-if-exception
+	    (begin (symlink (test-file) (test-symlink)) #t)))
+      (display "cannot create symlink, some readlink tests skipped\n")
+      (let ()
+        (pass-if-equal "file name of symlink" (test-file)
+          (readlink (test-symlink)))
+
+        (pass-if-equal "port representing a symlink" (test-file)
+          (let ()
+            (unless (and (provided? 'readlink-port)
+                         (defined? 'O_NOFOLLOW)
+                         (defined? 'O_PATH)
+                         (not (= 0 O_NOFOLLOW))
+                         (not (= 0 O_PATH)))
+              (throw 'unsupported))
+            (define port (open (test-symlink) (logior O_NOFOLLOW O_PATH)))
+            (define points-to (false-if-exception (readlink port)))
+            (close-port port)
+            points-to))
+
+        (pass-if-exception "not a port or file name" exception:wrong-type-arg
+          (readlink '(stuff)))))
+
+  (pass-if-equal "port representing a regular file" EINVAL
+    (call-with-input-file (test-file)
+      (lambda (port)
+        (unless (provided? 'readlink-port)
+          (throw 'unsupported))
+        (catch 'system-error
+          (lambda ()
+            (readlink port)
+            (close-port port) ; should be unreachable
+            #f)
+          (lambda args
+            (close-port port)
+            ;; At least Linux 5.10.46 returns ENOENT instead of EINVAL.
+            ;; Possibly surprising, but it is documented in some man
+            ;; pages and it doesn't appear to be an accident:
+            ;; <https://elixir.bootlin.com/linux/v5.10.46/source/fs/stat.c#L419>.
+            (define error (system-error-errno args))
+            (if (= error ENOENT)
+                EINVAL
+                error))))))
+
+  (pass-if-exception "non-file port" exception:wrong-type-arg
+    (readlink (open-input-string "")))
+
+  (pass-if-exception "closed port" exception:wrong-type-arg
+    (let ((port (open-file (test-file) "r")))
+      (close-port port)
+      (readlink port)))
+
+  (false-if-exception (delete-file (test-symlink)))
+  (false-if-exception (delete-file (test-file))))
-- 
2.30.2



debug log:

solving 211e0a4f4c ...
found 211e0a4f4c in https://yhetil.org/guix/20220320215031.306710-1-maximedevos@telenet.be/ ||
	https://yhetil.org/guix/4f4d275b86619feeb257b06c645395a92312608b.camel@telenet.be/

applying [1/1] https://yhetil.org/guix/20220320215031.306710-1-maximedevos@telenet.be/
diff --git a/gnu/packages/patches/guile-openat-and-friends-02.patch b/gnu/packages/patches/guile-openat-and-friends-02.patch
new file mode 100644
index 0000000000..211e0a4f4c

1:52: trailing whitespace.
 
1:65: trailing whitespace.
 
1:74: trailing whitespace.
 
1:75: trailing whitespace.
-SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0, 
1:109: trailing whitespace.
-  
Checking patch gnu/packages/patches/guile-openat-and-friends-02.patch...
Applied patch gnu/packages/patches/guile-openat-and-friends-02.patch cleanly.
warning: squelched 6 whitespace errors
warning: 11 lines add whitespace errors.

skipping https://yhetil.org/guix/4f4d275b86619feeb257b06c645395a92312608b.camel@telenet.be/ for 211e0a4f4c
index at:
100644 211e0a4f4ca56abf71040f52972bfd2677947849	gnu/packages/patches/guile-openat-and-friends-02.patch

(*) Git path names are given by the tree(s) the blob belongs to.
    Blobs themselves have no identifier aside from the hash of its contents.^

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.