[#6864] ruby 1.8.4 rc breaks alias_method/rails in bad ways — "Ara.T.Howard" <ara.t.howard@...>

20 messages 2005/12/09
[#6870] Re: ruby 1.8.4 rc breaks alias_method/rails in bad ways — =?ISO-8859-15?Q?Florian_Gro=DF?= <florgro@...> 2005/12/12

Ara.T.Howard wrote:

[#6872] Re: ruby 1.8.4 rc breaks alias_method/rails in bad ways — ara.t.howard@... 2005/12/12

On Tue, 13 Dec 2005, [ISO-8859-15] Florian Growrote:

[#6873] Re: ruby 1.8.4 rc breaks alias_method/rails in bad ways — James Edward Gray II <james@...> 2005/12/12

On Dec 12, 2005, at 1:19 PM, ara.t.howard@noaa.gov wrote:

[#6874] Re: ruby 1.8.4 rc breaks alias_method/rails in bad ways — ara.t.howard@... 2005/12/12

On Tue, 13 Dec 2005, James Edward Gray II wrote:

[#6891] Time.utc! and Time.localtime! — Daniel Hobe <hobe@...>

Writing a script yesterday I found out, much to my surprise, that the

16 messages 2005/12/14

[#6918] change to yaml in 1.8.4 — ara.t.howard@...

14 messages 2005/12/16

[#6934] 1.8.x, YAML, and release management — Ryan Davis <ryand-ruby@...>

I'm concerned that 1.8.3's acceptance of non-backwards-compatible

28 messages 2005/12/18

[#6996] Problems building 1.8.4 with VS8 C++ Express Edition (cl 14.00) — Austin Ziegler <halostatue@...>

Visual Studio C++ 2005 Express Edition (VS 8.0)

20 messages 2005/12/27

Re: [ ruby-Bugs-3155 ] Dir#seek segfaults on Windows XP

From: "H.Yamamoto" <ocean@...2.ccsnet.ne.jp>
Date: 2005-12-31 10:17:55 UTC
List: ruby-core #7038
Hi.

>But I think SEGV is not good even if so. I'll fix it.
>
># And I found my own bug on ruby 1.9 while survey.
># seekdir in win32/win32.c must update `bitpos`. :-(

This is patch. This is still hot, so I'll commit after my brain
cool down.

/////////////////////////////////////////
// ruby 1.9

Index: dir.h
===================================================================
RCS file: /src/ruby/win32/dir.h,v
retrieving revision 1.9
diff -u -w -b -p -r1.9 dir.h
--- dir.h	19 Jan 2004 12:28:14 -0000	1.9
+++ dir.h	31 Dec 2005 09:05:39 -0000
@@ -21,9 +21,9 @@ typedef struct {
     char *curr;
     long size;
     long nfiles;
+    long loc;  /* [0, nfiles) */
     struct direct dirstr;
     char *bits;  /* used for d_isdir and d_isrep */
-    long bitpos; /* used for d_isdir and d_isrep */
 } DIR;
 
 
Index: win32.c
===================================================================
RCS file: /src/ruby/win32/win32.c,v
retrieving revision 1.182
diff -u -w -b -p -r1.182 win32.c
--- win32.c	28 Nov 2005 04:21:24 -0000	1.182
+++ win32.c	31 Dec 2005 09:05:43 -0000
@@ -1345,8 +1345,8 @@ rb_w32_cmdvector(const char *cmd, char *
 // return the pointer to the current file name. 
 //
 
-#define GetBit(bits, i) ((bits)[(i) / 8] &  (1 << (i) % 8))
-#define SetBit(bits, i) ((bits)[(i) / 8] |= (1 << (i) % 8))
+#define GetBit(bits, loc, i) (bits[(loc * 2 + i) / 8] &  (1 << (loc * 2 + i) % 8))
+#define SetBit(bits, loc, i) (bits[(loc * 2 + i) / 8] |= (1 << (loc * 2 + i) % 8))
 
 DIR *
 rb_w32_opendir(const char *filename)
@@ -1413,9 +1413,9 @@ rb_w32_opendir(const char *filename)
     p->bits = ALLOC_N(char, 1);
     p->bits[0] = 0;
     if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-	SetBit(p->bits, 0);
+	SetBit(p->bits, p->nfiles, 0);
     if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
-	SetBit(p->bits, 1);
+	SetBit(p->bits, p->nfiles, 1);
     p->nfiles++;
     
     //
@@ -1448,9 +1448,9 @@ rb_w32_opendir(const char *filename)
 	    p->bits[p->nfiles / 4] = 0;
 	}
 	if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-	    SetBit(p->bits, p->nfiles * 2);
+	    SetBit(p->bits, p->nfiles, 0);
 	if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
-	    SetBit(p->bits, p->nfiles * 2 + 1);
+	    SetBit(p->bits, p->nfiles, 1);
 
 	p->nfiles++;
 	idx += len+1;
@@ -1461,6 +1461,21 @@ rb_w32_opendir(const char *filename)
     return p;
 }
 
+//
+// Move to next entry
+//
+
+static void
+move_to_next_entry(DIR *dirp)
+{
+    if (dirp->curr) {
+	dirp->loc++;
+	dirp->curr += strlen(dirp->curr) + 1;
+	if (dirp->curr >= (dirp->start + dirp->size)) {
+	    dirp->curr = NULL;
+	}
+    }
+}
 
 //
 // Readdir just returns the current string pointer and bumps the
@@ -1470,7 +1485,6 @@ rb_w32_opendir(const char *filename)
 struct direct  *
 rb_w32_readdir(DIR *dirp)
 {
-    int         len;
     static int  dummy = 0;
 
     if (dirp->curr) {
@@ -1479,9 +1493,8 @@ rb_w32_readdir(DIR *dirp)
 	// first set up the structure to return
 	//
 
-	len = strlen(dirp->curr);
 	strcpy(dirp->dirstr.d_name, dirp->curr);
-	dirp->dirstr.d_namlen = len;
+	dirp->dirstr.d_namlen = strlen(dirp->curr);
 
 	//
 	// Fake inode
@@ -1491,19 +1504,14 @@ rb_w32_readdir(DIR *dirp)
 	//
 	// Attributes
 	//
-	dirp->dirstr.d_isdir = GetBit(dirp->bits, dirp->bitpos);
-	dirp->bitpos++;
-	dirp->dirstr.d_isrep = GetBit(dirp->bits, dirp->bitpos);
-	dirp->bitpos++;
+	dirp->dirstr.d_isdir = GetBit(dirp->bits, dirp->loc, 0);
+	dirp->dirstr.d_isrep = GetBit(dirp->bits, dirp->loc, 1);
 
 	//
 	// Now set up for the next call to readdir
 	//
 
-	dirp->curr += len + 1;
-	if (dirp->curr >= (dirp->start + dirp->size)) {
-	    dirp->curr = NULL;
-	}
+	move_to_next_entry(dirp);
 
 	return &(dirp->dirstr);
 
@@ -1518,7 +1526,7 @@ rb_w32_readdir(DIR *dirp)
 long
 rb_w32_telldir(DIR *dirp)
 {
-	return (long) dirp->curr;	/* ouch! pointer to long cast */
+    return dirp->loc;
 }
 
 //
@@ -1528,7 +1536,11 @@ rb_w32_telldir(DIR *dirp)
 void
 rb_w32_seekdir(DIR *dirp, long loc)
 {
-	dirp->curr = (char *) loc;	/* ouch! long to pointer cast */
+    rb_w32_rewinddir(dirp);
+
+    while (--loc >= 0) {
+	move_to_next_entry(dirp);
+    }
 }
 
 //
@@ -1539,7 +1551,7 @@ void
 rb_w32_rewinddir(DIR *dirp)
 {
 	dirp->curr = dirp->start;
-	dirp->bitpos = 0;
+    dirp->loc = 0;
 }
 
 //


///////////////////////////////////////////
// ruby 1.8 (keep binary compatibility)

Index: win32.c
===================================================================
RCS file: /src/ruby/win32/win32.c,v
retrieving revision 1.103.2.38
diff -u -w -b -p -r1.103.2.38 win32.c
--- win32.c	29 Dec 2005 19:55:58 -0000	1.103.2.38
+++ win32.c	31 Dec 2005 10:04:13 -0000
@@ -1448,6 +1448,21 @@ rb_w32_opendir(const char *filename)
     return p;
 }
 
+//
+// Peek next dir entry
+//
+
+static char *
+next_entry(DIR *dirp, char *p)
+{
+    if (p) {
+	p += strlen(p) + 1;
+	if (p >= (dirp->start + dirp->size)) {
+	    p = NULL;
+	}
+    }
+    return p;
+}
 
 //
 // Readdir just returns the current string pointer and bumps the
@@ -1457,7 +1472,6 @@ rb_w32_opendir(const char *filename)
 struct direct  *
 rb_w32_readdir(DIR *dirp)
 {
-    int         len;
     static int  dummy = 0;
 
     if (dirp->curr) {
@@ -1466,9 +1480,8 @@ rb_w32_readdir(DIR *dirp)
 	// first set up the structure to return
 	//
 
-	len = strlen(dirp->curr);
 	strcpy(dirp->dirstr.d_name, dirp->curr);
-	dirp->dirstr.d_namlen = len;
+	dirp->dirstr.d_namlen = strlen(dirp->curr);
 
 	//
 	// Fake inode
@@ -1479,10 +1492,7 @@ rb_w32_readdir(DIR *dirp)
 	// Now set up for the next call to readdir
 	//
 
-	dirp->curr += len + 1;
-	if (dirp->curr >= (dirp->start + dirp->size)) {
-	    dirp->curr = NULL;
-	}
+	dirp->curr = next_entry(dirp, dirp->curr);
 
 	return &(dirp->dirstr);
 
@@ -1497,7 +1507,12 @@ rb_w32_readdir(DIR *dirp)
 long
 rb_w32_telldir(DIR *dirp)
 {
-	return (long) dirp->curr;	/* ouch! pointer to long cast */
+    char *p; long loc = 0;
+
+    for (p = dirp->start; p != dirp->curr; p = next_entry(dirp, p)) {
+	loc++;
+    }
+    return loc;
 }
 
 //
@@ -1507,7 +1522,11 @@ rb_w32_telldir(DIR *dirp)
 void
 rb_w32_seekdir(DIR *dirp, long loc)
 {
-	dirp->curr = (char *) loc;	/* ouch! long to pointer cast */
+    dirp->curr = dirp->start;
+
+    while (--loc >= 0) {
+	dirp->curr = next_entry(dirp, dirp->curr);
+    }
 }
 
 //

////////////////////////////////////
// test case

require 'test/unit'

require 'tmpdir'
require 'fileutils'

class TestDir < Test::Unit::TestCase

  ROOT = File.join(Dir.tmpdir, "__test_dir__#{$$}")

  def setup
    Dir.mkdir(ROOT)
    for i in ?a..?z
      if i % 2 == 0
        FileUtils.touch(File.join(ROOT, i.chr))
      else
        FileUtils.mkdir(File.join(ROOT, i.chr))
      end
    end
  end

  def teardown
    FileUtils.rm_rf ROOT if File.directory?(ROOT)
  end

  def test_seek
    dir = Dir.open(ROOT)
    begin
      cache = []
      loop do
        pos = dir.tell
        break unless name = dir.read
        cache << [pos, name]
      end
      cache.sort_by { rand }
      for x in cache
        dir.seek(x[0])
        assert_equal(x[1], dir.read)
      end
    ensure
      dir.close
    end
  end
end


In This Thread