FAQ SearchLogin
Tuxera Home
View unanswered posts | View active topics It is currently Sat May 15, 2021 03:58



Post new topic Reply to topic  [ 3 posts ] 
readdir returning invalid results for junction points 
Author Message

Joined: Fri Aug 17, 2012 17:10
Posts: 2
Post readdir returning invalid results for junction points
Hi,

While using Baobab (a Linux tool to check disk usage) I stumbled across a bug which is probably caused by ntfs-3g.
GLib bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=672219

The issue is that the readdir syscall returns an invalid result for junction points/symbolic links on NTFS volumes.
The readdir syscall returns a 'struct dirent' containing information about all files and directories in a folder.
This structure contains a field called d_type which is used to indicate the type of the file in question.
Some possible values are DT_DIR for directories, DT_REG for regular files and DT_LNK for symbolic links.

When trying to perform a readdir on a NTFS folder which contains a junction point (for example the root on a NTFS volume with Windows 7 installed which contains a junction point called 'Documents and Settings' which points to the 'Users' folder) then the d_type field contains the value DT_DIR for any detected junction points. I consider this an invalid value as a junction point isn't really a directory, but is a symbolic link (in UNIX terminology). Therefore I expect the d_type field to have the value DT_LNK.

Here's a simple testcase to illustrate this behaviour:
Code:
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>

const char *get_d_type_str(unsigned char d_type)
{
   switch (d_type) {
      case DT_BLK: return "Block device";
      case DT_CHR: return "Character device";
      case DT_DIR: return "Directory";
      case DT_FIFO: return "Named pipe (FIFO)";
      case DT_LNK: return "Symbolic link";
      case DT_REG: return "Regular file";
      case DT_SOCK: return "UNIX domain socket";
      case DT_UNKNOWN:
      default:
         return "Unknown";
   }
}

const char *get_st_mode(mode_t st_mode)
{
   if (S_ISBLK(st_mode)) return "Block device";
   if (S_ISCHR(st_mode)) return "Character device";
   if (S_ISDIR(st_mode)) return "Directory";
   if (S_ISFIFO(st_mode)) return "Named pipe (FIFO)";
   if (S_ISLNK(st_mode)) return "Symbolic link";
   if (S_ISREG(st_mode)) return "Regular file";
   if (S_ISSOCK(st_mode)) return "UNIX domain socket";
   return "Unknown";
}

int main(int argc, char **argv)
{
   DIR *dir;
   struct dirent *di;

   if (argc != 2) {
      printf("Usage: %s folder\n", argv[0]);
      return 1;
   }

   dir = opendir(argv[1]);
   if (!dir) {
      printf("Unable to opendir %s: %s\n", argv[1], strerror(errno));
      return 1;
   }

   while (di = readdir(dir)) {
      char path[256];
      struct stat st;

      memset(path, 0, sizeof(path));
      snprintf(path, sizeof(path), "%s/%s", argv[1], di->d_name);
      if (lstat(path, &st) != 0) {
         printf("Unable to stat %s: %s\n", path, strerror(errno));
         continue;
      }

      printf("di.d_name = %s - di.d_type = %i (%s) - st.st_mode = %i (%s)\n", di->d_name, di->d_type, get_d_type_str(di->d_type), st.st_mode, get_st_mode(st.st_mode));
   }

   closedir(dir);

   return 0;
}


When this command is run on a Linux (ext4) folder which contains a symbolic link (pointing to a directory) then it returns these results:
<snip>
di.d_name = my_symlink - di.d_type = 10 (Symbolic link) - st.st_mode = 41471 (Symbolic link)
</snip>

However, when I run this on a NTFS volume containing Windows 7 then I get these results:
<snip>
di.d_name = Documents and Settings - di.d_type = 4 (Directory) - st.st_mode = 41471 (Symbolic link)
</snip>

As you can see both the readdir and lstat syscalls correctly detect the symbolic link on the ext4 volume, but on the NTFS volume only the lstat syscall indicates that the file in question is a symbolic link while the readdir syscall indicates that the file is a directory.

Please fix this behaviour so that the readdir syscall sets the d_type to 10 (Symbolic link) whenever a junction point is detected


Fri Aug 17, 2012 17:59
Profile
NTFS-3G Lead Developer

Joined: Tue Sep 04, 2007 17:22
Posts: 1286
Post Re: readdir returning invalid results for junction points
Hi,

Quote:
I stumbled across a bug which is probably caused by ntfs-3g.

Thank you for your detailed report.
Quote:
Please fix this behaviour so that the readdir syscall sets the d_type to 10 (Symbolic link) whenever a junction point is detected

Sure, please test the attached patch.

Regards

Jean-Pierre


Attachments:
patches73.gz [1.72 KiB]
Downloaded 918 times
Sat Aug 18, 2012 11:14
Profile

Joined: Fri Aug 17, 2012 17:10
Posts: 2
Post Re: readdir returning invalid results for junction points
Hi,

Thank you very much for the quick fix!
I just tested it on a Fedora 17 x86_64 environment and the readdir syscall now returns the correct value for the 'Documents and Settings' junction point:
<snip>
di.d_name = Documents and Settings - di.d_type = 10 (Symbolic link) - st.st_mode = 41471 (Symbolic link)
</snip>

The baobab issue which was my initial problem is also resolved automatically due to this patch.
I'll propose the patch to the ntfs-3g package maintainer in Fedora so he can apply it for now until the next ntfs-3g released


Sat Aug 18, 2012 14:46
Profile
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Original forum style by Vjacheslav Trushkin.