--- dmd2_040/src/phobos/std/file.d	2010-01-28 20:43:18.000000000 -0800
+++ dmd2/src/phobos/std/file.d	2010-02-24 00:18:06.126371087 -0800
@@ -108,6 +108,7 @@
     
     extern(C) int fstat64(int, struct_stat64*);
     extern(C) int stat64(in char*, struct_stat64*);
+    extern(C) int lstat64(in char*, struct_stat64*);
 }
 // }}}
 
@@ -647,6 +648,30 @@
     return statbuf.st_mode;
 }
 
+/***************************************************
+Get file $(D name) attributes. The differenc between
+$(D getLinkAttributes) and $(D getAttributes) is that
+$(D getLinkAttributes)  when $(D name) is a symbolic
+link, it returns the attributes for the link itself rather
+than the file that it points to. If $(D name) is not a
+symbolic link, then the result is the same as
+$(D getAttributes).
+
+Throws: $(D FileException) on error.
+ */
+
+version(Windows) uint getLinkAttributes(in char[] name)
+{
+    return getAttributes(name);
+}
+
+version(Posix) uint getLinkAttributes(in char[] name)
+{
+    struct_stat64 statbuf = void;
+    cenforce(lstat64(toStringz(name), &statbuf) == 0, name);
+    return statbuf.st_mode;
+}
+
 /****************************************************
  * Is $(D name) a directory?
  * Throws: $(D FileException) if $(D name) doesn't exist.
@@ -659,7 +684,7 @@
 
 version(Posix) bool isdir(in char[] name)
 {
-    return (getAttributes(name) & S_IFMT) == S_IFDIR;
+    return (getLinkAttributes(name) & S_IFMT) == S_IFDIR;
 }
 
 /****************************************************
@@ -674,9 +699,25 @@
 
 version(Posix) bool isfile(in char[] name)
 {
-    return (getAttributes(name) & S_IFMT) == S_IFREG;        // regular file
+    return (getLinkAttributes(name) & S_IFMT) == S_IFREG;        // regular file
 }
-    
+
+/****************************************************
+ * Is $(D name) a symbolic link?
+ *
+ * Throws: $(D FileException) if $(D name) doesn't exist.
+ */
+
+version(Windows) bool issymlink(in char[] name)
+{
+    return false;
+}
+
+version(Posix) bool issymlink(in char[] name)
+{
+    return (getLinkAttributes(name) & S_IFMT) == S_IFLNK;        // symbolic link
+}
+
 /****************************************************
  * Change directory to $(D pathname).
  * Throws: $(D FileException) on error.
@@ -860,6 +901,25 @@
     {
         return !isdir;
     }
+
+    /****
+     * Return !=0 if DirEntry is a symbolic link.
+     */
+    bool issymlink() const
+    {
+        return false;
+    }
+
+    /****
+      * If this ($D DirEntry) is for a symbolic link, this
+      * returns a ($D DirEntry) for the file that it points
+      * to. If this ($D DirEntry) is not a symbolic link,
+      * then it returns a copy of this DirEntry.
+      */
+    DirEntry followLink() const
+    {
+        return this;
+    }
 }
 
 version(Posix) struct DirEntry
@@ -891,6 +951,11 @@
         return (d_type & DT_REG) != 0;
     }
         
+    bool issymlink() const
+    {
+        return (d_type & DT_LNK) != 0;
+    }
+        
     ulong size()
     {
         ensureStatDone;
@@ -922,7 +987,7 @@
     void ensureStatDone()
     {
         if (didstat) return;
-        enforce(stat64(toStringz(name), &statbuf) == 0,
+        enforce(lstat64(toStringz(name), &statbuf) == 0,
                 "Failed to stat file `"~name~"'");
         _size = statbuf.st_size;
         _creationTime = cast(d_time)statbuf.st_ctime
@@ -933,6 +998,51 @@
             * std.date.ticksPerSecond;
         didstat = true;
     }
+
+    DirEntry followLink() const
+    {
+        if(!issymlink())
+            return this;
+
+        DirEntry pointedTo;
+
+        enforce(stat64(toStringz(name), &pointedTo.statbuf) == 0,
+                "Failed to stat file `"~name~"'");
+        pointedTo.name = name.idup;
+
+        pointedTo._size = pointedTo.statbuf.st_size;
+        pointedTo._creationTime = cast(d_time)pointedTo.statbuf.st_ctime
+            * std.date.ticksPerSecond;
+        pointedTo._lastAccessTime = cast(d_time)pointedTo.statbuf.st_atime
+            * std.date.ticksPerSecond;
+        pointedTo._lastWriteTime = cast(d_time)pointedTo.statbuf.st_mtime
+            * std.date.ticksPerSecond;
+        pointedTo.didstat = true;
+
+        const uint mode = statbuf.st_mode;
+        if((mode & S_IFIFO) != 0)
+            pointedTo.d_type = DT_FIFO;
+        else if((mode & S_IFCHR) != 0)
+            pointedTo.d_type = DT_CHR;
+        else if((mode & S_IFDIR) != 0)
+            pointedTo.d_type = DT_DIR;
+        else if((mode & S_IFBLK) != 0)
+            pointedTo.d_type = DT_BLK;
+        else if((mode & S_IFREG) != 0)
+            pointedTo.d_type = DT_REG;
+        else if((mode & S_IFLNK) != 0)
+            pointedTo.d_type = DT_LNK;
+        else if((mode & S_IFSOCK) != 0)
+            pointedTo.d_type = DT_SOCK;
+        else if((mode & S_IFSOCK) != 0)
+            pointedTo.d_type = DT_SOCK;
+        //else if((mode & ???) != 0)
+            //pointedTo.d_type = DT_WHT;
+        else
+            pointedTo.d_type = DT_UNKNOWN;
+
+        return pointedTo;
+    }
 }
 
 /******************************************************
