1Fix Gnulib's getcwd in chroots.
2From Debian bug #456164, http://bugs.debian.org/456164 .
3
4--- cvs-1.12.13.orig/debian/patches/20_readdir_errno
5+++ cvs-1.12.13/debian/patches/20_readdir_errno
6@@ -0,0 +1,121 @@
7+# From Gnulib:
8+# http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commitdiff;h=0b78641d85af3b72e3b9d94cb7b94e45f3c08ee5
9+# We don't need this directly, but it's required so that 21_getcwd_chroot
10+# applies cleanly.
11+#
12+# 2005-10-29 Paul Eggert <eggert@cs.ucla.edu>
13+#
14+# * getcwd.c (__getcwd): Don't assume that system calls after readdir
15+# leave errno alone. Problem reported by Dmitry V. Levin.
16+
17+--- cvs-1.12.13-old/lib/getcwd.c
18++++ cvs-1.12.13/lib/getcwd.c
19+@@ -201,6 +201,8 @@ __getcwd (char *buf, size_t size)
20+ ino_t dotino;
21+ bool mount_point;
22+ int parent_status;
23++ size_t dirroom;
24++ size_t namlen;
25+
26+ /* Look at the parent directory. */
27+ #ifdef AT_FDCWD
28+@@ -241,11 +243,20 @@ __getcwd (char *buf, size_t size)
29+ goto lose;
30+ dotlist[dotlen++] = '/';
31+ #endif
32+- /* Clear errno to distinguish EOF from error if readdir returns
33+- NULL. */
34+- __set_errno (0);
35+- while ((d = __readdir (dirstream)) != NULL)
36++ for (;;)
37+ {
38++ /* Clear errno to distinguish EOF from error if readdir returns
39++ NULL. */
40++ __set_errno (0);
41++ d = __readdir (dirstream);
42++ if (d == NULL)
43++ {
44++ if (errno == 0)
45++ /* EOF on dirstream, which means that the current directory
46++ has been removed. */
47++ __set_errno (ENOENT);
48++ goto lose;
49++ }
50+ if (d->d_name[0] == '.' &&
51+ (d->d_name[1] == '\0' ||
52+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
53+@@ -303,48 +314,38 @@ __getcwd (char *buf, size_t size)
54+ break;
55+ }
56+ }
57+- if (d == NULL)
58+- {
59+- if (errno == 0)
60+- /* EOF on dirstream, which means that the current directory
61+- has been removed. */
62+- __set_errno (ENOENT);
63+- goto lose;
64+- }
65+- else
66+- {
67+- size_t dirroom = dirp - dir;
68+- size_t namlen = _D_EXACT_NAMLEN (d);
69+
70+- if (dirroom <= namlen)
71++ dirroom = dirp - dir;
72++ namlen = _D_EXACT_NAMLEN (d);
73++
74++ if (dirroom <= namlen)
75++ {
76++ if (size != 0)
77+ {
78+- if (size != 0)
79+- {
80+- __set_errno (ERANGE);
81+- goto lose;
82+- }
83+- else
84+- {
85+- char *tmp;
86+- size_t oldsize = allocated;
87++ __set_errno (ERANGE);
88++ goto lose;
89++ }
90++ else
91++ {
92++ char *tmp;
93++ size_t oldsize = allocated;
94+
95+- allocated += MAX (allocated, namlen);
96+- if (allocated < oldsize
97+- || ! (tmp = realloc (dir, allocated)))
98+- goto memory_exhausted;
99++ allocated += MAX (allocated, namlen);
100++ if (allocated < oldsize
101++ || ! (tmp = realloc (dir, allocated)))
102++ goto memory_exhausted;
103+
104+- /* Move current contents up to the end of the buffer.
105+- This is guaranteed to be non-overlapping. */
106+- dirp = memcpy (tmp + allocated - (oldsize - dirroom),
107+- tmp + dirroom,
108+- oldsize - dirroom);
109+- dir = tmp;
110+- }
111++ /* Move current contents up to the end of the buffer.
112++ This is guaranteed to be non-overlapping. */
113++ dirp = memcpy (tmp + allocated - (oldsize - dirroom),
114++ tmp + dirroom,
115++ oldsize - dirroom);
116++ dir = tmp;
117+ }
118+- dirp -= namlen;
119+- memcpy (dirp, d->d_name, namlen);
120+- *--dirp = '/';
121+ }
122++ dirp -= namlen;
123++ memcpy (dirp, d->d_name, namlen);
124++ *--dirp = '/';
125+
126+ thisdev = dotdev;
127+ thisino = dotino;
128--- cvs-1.12.13.orig/debian/patches/21_getcwd_chroot
129+++ cvs-1.12.13/debian/patches/21_getcwd_chroot
130@@ -0,0 +1,172 @@
131+# From Gnulib:
132+# http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commitdiff;h=79c0a43808d9ca85acd04600149fc1a9b75bd1b9
133+#
134+# 2006-07-03 Paul Eggert <eggert@cs.ucla.edu>
135+#
136+# Merge from coreutils.
137+#
138+# 2006-03-19 Jim Meyering <jim@meyering.net>
139+#
140+# Work even in a chroot where d_ino values for entries in "/"
141+# don't match the stat.st_ino values for the same names.
142+# * getcwd.c (__getcwd): When no d_ino value matches the target inode
143+# number, iterate through all entries again, using lstat instead.
144+# Reported by Kenshi Muto in http://bugs.debian.org/355810, and by
145+# Zouhir Hafidi in https://bugzilla.redhat.com/bugzilla/190656.
146+#
147+# * getcwd.c (__getcwd): Clarify a comment.
148+# Use memcpy in place of a call to strcpy.
149+
150+--- cvs-1.12.13-old/lib/getcwd.c
151++++ cvs-1.12.13/lib/getcwd.c
152+@@ -211,6 +211,7 @@ __getcwd (char *buf, size_t size)
153+ int parent_status;
154+ size_t dirroom;
155+ size_t namlen;
156++ bool use_d_ino = true;
157+
158+ /* Look at the parent directory. */
159+ #ifdef AT_FDCWD
160+@@ -257,11 +258,26 @@ __getcwd (char *buf, size_t size)
161+ NULL. */
162+ __set_errno (0);
163+ d = __readdir (dirstream);
164++
165++ /* When we've iterated through all directory entries without finding
166++ one with a matching d_ino, rewind the stream and consider each
167++ name again, but this time, using lstat. This is necessary in a
168++ chroot on at least one system (glibc-2.3.6 + linux 2.6.12), where
169++ .., ../.., ../../.., etc. all had the same device number, yet the
170++ d_ino values for entries in / did not match those obtained
171++ via lstat. */
172++ if (d == NULL && errno == 0 && use_d_ino)
173++ {
174++ use_d_ino = false;
175++ rewinddir (dirstream);
176++ d = __readdir (dirstream);
177++ }
178++
179+ if (d == NULL)
180+ {
181+ if (errno == 0)
182+- /* EOF on dirstream, which means that the current directory
183+- has been removed. */
184++ /* EOF on dirstream, which can mean e.g., that the current
185++ directory has been removed. */
186+ __set_errno (ENOENT);
187+ goto lose;
188+ }
189+@@ -269,58 +285,65 @@ __getcwd (char *buf, size_t size)
190+ (d->d_name[1] == '\0' ||
191+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
192+ continue;
193+- if (MATCHING_INO (d, thisino) || mount_point)
194++
195++ if (use_d_ino)
196+ {
197+- int entry_status;
198++ bool match = (MATCHING_INO (d, thisino) || mount_point);
199++ if (! match)
200++ continue;
201++ }
202++
203++ {
204++ int entry_status;
205+ #ifdef AT_FDCWD
206+- entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
207++ entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
208+ #else
209+- /* Compute size needed for this file name, or for the file
210+- name ".." in the same directory, whichever is larger.
211+- Room for ".." might be needed the next time through
212+- the outer loop. */
213+- size_t name_alloc = _D_ALLOC_NAMLEN (d);
214+- size_t filesize = dotlen + MAX (sizeof "..", name_alloc);
215+-
216+- if (filesize < dotlen)
217+- goto memory_exhausted;
218+-
219+- if (dotsize < filesize)
220+- {
221+- /* My, what a deep directory tree you have, Grandma. */
222+- size_t newsize = MAX (filesize, dotsize * 2);
223+- size_t i;
224+- if (newsize < dotsize)
225+- goto memory_exhausted;
226+- if (dotlist != dots)
227+- free (dotlist);
228+- dotlist = malloc (newsize);
229+- if (dotlist == NULL)
230+- goto lose;
231+- dotsize = newsize;
232+-
233+- i = 0;
234+- do
235+- {
236+- dotlist[i++] = '.';
237+- dotlist[i++] = '.';
238+- dotlist[i++] = '/';
239+- }
240+- while (i < dotlen);
241+- }
242+-
243+- strcpy (dotlist + dotlen, d->d_name);
244+- entry_status = __lstat (dotlist, &st);
245++ /* Compute size needed for this file name, or for the file
246++ name ".." in the same directory, whichever is larger.
247++ Room for ".." might be needed the next time through
248++ the outer loop. */
249++ size_t name_alloc = _D_ALLOC_NAMLEN (d);
250++ size_t filesize = dotlen + MAX (sizeof "..", name_alloc);
251++
252++ if (filesize < dotlen)
253++ goto memory_exhausted;
254++
255++ if (dotsize < filesize)
256++ {
257++ /* My, what a deep directory tree you have, Grandma. */
258++ size_t newsize = MAX (filesize, dotsize * 2);
259++ size_t i;
260++ if (newsize < dotsize)
261++ goto memory_exhausted;
262++ if (dotlist != dots)
263++ free (dotlist);
264++ dotlist = malloc (newsize);
265++ if (dotlist == NULL)
266++ goto lose;
267++ dotsize = newsize;
268++
269++ i = 0;
270++ do
271++ {
272++ dotlist[i++] = '.';
273++ dotlist[i++] = '.';
274++ dotlist[i++] = '/';
275++ }
276++ while (i < dotlen);
277++ }
278++
279++ memcpy (dotlist + dotlen, d->d_name, _D_ALLOC_NAMLEN (d));
280++ entry_status = __lstat (dotlist, &st);
281+ #endif
282+- /* We don't fail here if we cannot stat() a directory entry.
283+- This can happen when (network) file systems fail. If this
284+- entry is in fact the one we are looking for we will find
285+- out soon as we reach the end of the directory without
286+- having found anything. */
287+- if (entry_status == 0 && S_ISDIR (st.st_mode)
288+- && st.st_dev == thisdev && st.st_ino == thisino)
289+- break;
290+- }
291++ /* We don't fail here if we cannot stat() a directory entry.
292++ This can happen when (network) file systems fail. If this
293++ entry is in fact the one we are looking for we will find
294++ out soon as we reach the end of the directory without
295++ having found anything. */
296++ if (entry_status == 0 && S_ISDIR (st.st_mode)
297++ && st.st_dev == thisdev && st.st_ino == thisino)
298++ break;
299++ }
300+ }
301+
302+ dirroom = dirp - dir;