at master 302 lines 9.4 kB view raw
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;