3

I am working at an OS independent file manager, and I divide files in groups, usually based on the extension. On Linux, I check if a file has the executable permissions or not, and if it does, I add it to the executables group. This works great for Windows or Linux, but if you combine them it doesn't work so well. For example, while using it on Linux and exploring a windows mounted drive, all the files appear to be executable. I am trying to find a way to ignore those files and not add them to the executables group. My code (on Linux) uses stat:

#ifndef WINDOWS
stat(ep->d_name, &buf);
....
if(!files_list[i].is_dir && buf.st_mode & 0111)
files_list[i].is_exe=1;
#endif
Radu
  • 923
  • 2
  • 9
  • 21
  • Is it portable code that runs either on Linux or on Windows or code that runs only on Linux and accesses both Linux-centric and Windows-centric filesystems? – mouviciel Sep 20 '11 at 07:33
  • It is portable code that runs on both Windows and Linux (see the #ifdef WINDOWS part). – Radu Sep 20 '11 at 07:39
  • So the solution is obvious: `#ifdef WINDOWS /* check extention */ #else /* check x bit */ #endif` – mouviciel Sep 20 '11 at 07:42
  • This is how my code works so far.. Reread the question please. – Radu Sep 20 '11 at 07:45
  • I read your question. I also read your answer to my previous question. From your second answer it appears that you access to FAT system from Linux, which is not what `#ifndef WINDOWS` suggests. The only solution I see (besides the `file` utility) is to dive into disk formats, partition tables (MBR, GUID), partitions and filesystems at the device level. For an example, you may want to check [`gparted` source code](http://gparted.sourceforge.net/). – mouviciel Sep 20 '11 at 08:06
  • I access ANY file system from Linux. The #ifdef is so that the code can run both on Linux and Windows. – Radu Sep 20 '11 at 08:07
  • But then I would also have to look in fstab to see where they are mounted, and so on (and not even sure if I can do that as non root), I would like a more simple solution if possible.. – Radu Sep 20 '11 at 08:09

3 Answers3

4

The first part of the answer is to find what filesystem the file is mounted on. To do that you need to find the filesystem using the st_dev field of the stat information for the file. (You can also do this by checking the file path, but you then have to check every path element for symbolic links).

You can then cross-reference the st_dev field with the mount table in /proc/mounts using getmntent_r(). There's an example of that in a previous answer. The mnt_type field will give you the text of the filesystem type, and you'll need to compare the string with a list of Windows filesystems.

Once you've found the filesystem, the only way to identify an executable is by heuristics. As other people have suggested, you can look at the file extension for Windows executables, and look at the initial bytes of the file for Linux executables. Don't forget executable scripts with the #! prefix, and you may need to read into a Jar file to find out if it contains an executable static main() method.

Community
  • 1
  • 1
Adrian Cox
  • 6,204
  • 5
  • 41
  • 68
  • Thanks, this seems to be the most efficient way. I am mainly interested in the file system type, if FAT or NTFS I guess I can just assume there are no Linux executable files (it is not the end of the world if I miss some). I will have to look through that code you suggested and see exactly how it works. – Radu Sep 20 '11 at 08:37
  • If you're doing this in a file manager, you can cache the result of reading mount table to make the lookup faster. You'll just have to be careful to re-read the mount table whenever the user changes removable media. – Adrian Cox Sep 20 '11 at 08:43
  • Another point I've thought of: FUSE complicates things, as you really can't tell how a FUSE filesystem will behave. You can either treat all FUSE filesystems as Windows filesystems, or look at the `mnt_fsname` field to try and tell them apart. – Adrian Cox Sep 20 '11 at 08:46
  • Yeah, I can already see how this is going to turn in a very long project, just implementing the Linux related stuff (I also have to check for links, and other fun stuff) :) And of course, the windows files with the exe/com/bat extension should sort of be treated like executables too, just in case the use has Wine installed. – Radu Sep 20 '11 at 08:57
0

If you are browsing Windows files then you need to apply Windows rules for whether or not a file is executable. If the file extension is .EXE, .COM, .BAT, or .CMD then it is executable. If you want a more complete list then you should check MSDN. Note that it is possible to add registry entries on a machine that makes any extension you want to be considered executable, but it is best to ignore that kind of thing when you are browsing a drive from the network.

The fact is that you are fighting an uphill battle. The reason all the files have executable permissions is that the windows filesystem driver on Linux allows you to specify that as an option. This masks whether or not any files are Linux exceutables, for instance.

However, you could look into the file header for EVERY file and see if it is a Linux ELF executable (just like the Linux file command does).

It might be helpful to start by checking all the information about mounted filesystems so that you know what you are dealing with. For instance, do you have a CIFS filesystem mounted that is actually a Linux filesystem served up by SAMBA? If you enumerate every bit of information available about the mounted filesystem plus the complete set of stat info, you can probably identify combinations that act as fingerprints of the different scenarios.

Michael Dillon
  • 31,973
  • 6
  • 70
  • 106
  • Obviously. The problem I have is how do I know I am browsing Windows files? – Radu Sep 20 '11 at 07:27
  • You can also have Linux executables on a FAT formatted partition – Matteo Sep 20 '11 at 07:31
  • One clue would be that all the files have execute permissions set, as you mentioned in your question. – Michael Dillon Sep 20 '11 at 07:33
  • So does the directory /bin, /sbin, etc. – Radu Sep 20 '11 at 07:34
  • @Matteo, I am aware of that, but most of the times that is not the case. It would be nice if I could find out exactly which files are executables (like maybe look for the elf or sh signatures) but that is a bit overkillish for now. – Radu Sep 20 '11 at 07:36
  • I could do the file checking, but that would probably be pretty slow (you need an open, seek, read, close for each file). Besides, you need to check for scripts too. What I would like to find is some sort of function that tells you what kind of FS a directory or file resides on. – Radu Sep 20 '11 at 07:44
  • Parse `/etc/fstab` on linux to get that info. On windows i think it's more complicated but you could start with: http://msdn.microsoft.com/en-us/library/aa364001%28v=VS.85%29.aspx – RedX Sep 20 '11 at 08:13
  • Parsing fstab did cross my mind actually, but I was thinking there would be an easier way. On windows I don't need to actually do that, thankfully. – Radu Sep 20 '11 at 08:50
0

Another option I could imagine, is to call the file util, and depend on its output (maybe its enough to grep for the words executable / script). This util exist/is compileable for windows (basically it just checks for some magic bytes in the files), too.

flolo
  • 15,148
  • 4
  • 32
  • 57
  • That would work, but would be very slow, especially in directories with like 1K+ files. And would probably also trash the I/O cache. – Radu Sep 20 '11 at 08:05
  • You could cache the results. Then you would have the time penalty just once. – flolo Sep 20 '11 at 08:18
  • Yeah, but the problem is, if the user needs to wait like 10-15 seconds to open a big directory, it would be quite frustrating. There are other operations done on the files as well, such as sorting, getting date or size, etc. – Radu Sep 20 '11 at 08:20