Avoid possible overflow in fn_identity.
[pspp] / src / data / file-name.c
index 1b31048e211b75dd301fc87d5c928cfe0bc764f6..f59b2fa4ecd9bdcc367c1acffefe017859e6ad13 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@
 #include "libpspp/version.h"
 
 #include "gl/dirname.h"
+#include "gl/dosname.h"
 #include "gl/intprops.h"
 #include "gl/minmax.h"
 #include "gl/relocatable.h"
@@ -81,14 +82,6 @@ fn_search_path (const char *base_name, char **path)
   return NULL;
 }
 
-/* Returns the directory part of FILE_NAME, as a malloc()'d
-   string. */
-char *
-fn_dir_name (const char *file_name)
-{
-  return dir_name (file_name);
-}
-
 /* Returns the extension part of FILE_NAME as a malloc()'d string.
    If FILE_NAME does not have an extension, returns an empty
    string. */
@@ -110,52 +103,18 @@ fn_is_absolute (const char *name)
   return IS_ABSOLUTE_FILE_NAME (name);
 }
 
-/* Returns true if FILE_NAME is a virtual file that doesn't
-   really exist on disk, false if it's a real file name. */
-bool
-fn_is_special (const char *file_name)
-{
-  if (!strcmp (file_name, "-") || !strcmp (file_name, "stdin")
-      || !strcmp (file_name, "stdout") || !strcmp (file_name, "stderr")
-#ifdef HAVE_POPEN
-      || file_name[0] == '|'
-      || (*file_name && file_name[strlen (file_name) - 1] == '|')
-#endif
-      )
-    return true;
-
-  return false;
-}
-
-/* Returns true if file with name NAME exists. */
+/* Returns true if file with name NAME exists, and that file is not a
+   directory */
 bool
 fn_exists (const char *name)
 {
   struct stat temp;
-  return stat (name, &temp) == 0;
-}
-\f
-/* Environment variables. */
+  if ( stat (name, &temp) != 0 )
+    return false;
 
-/* Simulates $VER and $ARCH environment variables. */
-const char *
-fn_getenv (const char *s)
-{
-  if (!strcmp (s, "VER"))
-    return fn_getenv_default ("STAT_VER", bare_version);
-  else if (!strcmp (s, "ARCH"))
-    return fn_getenv_default ("STAT_ARCH", host_system);
-  else
-    return getenv (s);
+  return ! S_ISDIR (temp.st_mode);
 }
 
-/* Returns getenv(KEY) if that's non-NULL; else returns DEF. */
-const char *
-fn_getenv_default (const char *key, const char *def)
-{
-  const char *value = getenv (key);
-  return value ? value : def;
-}
 \f
 /* Basic file handling. */
 
@@ -165,7 +124,7 @@ fn_getenv_default (const char *key, const char *def)
 static FILE *
 safety_violation (const char *fn)
 {
-  msg (SE, _("Not opening pipe file `%s' because SAFER option set."), fn);
+  msg (SE, _("Not opening pipe file `%s' because %s option set."), fn, "SAFER");
   errno = EPERM;
   return NULL;
 }
@@ -221,14 +180,7 @@ fn_open (const char *fn, const char *mode)
     }
   else
 #endif
-    {
-      FILE *f = fopen (fn, mode);
-
-      if (f && mode[0] != 'r')
-       setvbuf (f, NULL, _IOLBF, 0);
-
-      return f;
-    }
+    return fopen (fn, mode);
 }
 
 /* Counterpart to fn_open that closes file F with name FN; returns 0
@@ -252,29 +204,6 @@ fn_close (const char *fn, FILE *f)
     return fclose (f);
 }
 
-/* Creates a new file named FN with the given PERMISSIONS bits,
-   and returns a stream for it or a null pointer on failure.
-   MODE should be "w" or "wb". */
-FILE *
-create_stream (const char *fn, const char *mode, mode_t permissions)
-{
-  int fd;
-  FILE *stream;
-
-  fd = open (fn, O_WRONLY | O_CREAT | O_TRUNC, permissions);
-  if (fd < 0)
-    return NULL;
-
-  stream = fdopen (fd, mode);
-  if (stream == NULL)
-    {
-      int save_errno = errno;
-      close (fd);
-      errno = save_errno;
-    }
-
-  return stream;
-}
 
 /* A file's identity:
 
@@ -291,8 +220,8 @@ create_stream (const char *fn, const char *mode, mode_t permissions)
    there. */
 struct file_identity
 {
-  dev_t device;               /* Device number. */
-  ino_t inode;                /* Inode number. */
+  unsigned long long device;               /* Device number. */
+  unsigned long long inode;                /* Inode number. */
   char *name;                 /* File name, where needed, otherwise NULL. */
 };
 
@@ -333,12 +262,42 @@ fn_get_identity (const char *file_name)
       free (dir);
     }
 #else /* Windows */
-  char cname[PATH_MAX];
-  int ok = GetFullPathName (file_name, sizeof cname, cname, NULL);
-  identity->device = 0;
-  identity->inode = 0;
-  identity->name = xstrdup (ok ? cname : file_name);
-  str_lowercase (identity->name);
+  bool ok = false;
+  HANDLE h = CreateFile (file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+  if (h != INVALID_HANDLE_VALUE)
+  {
+    BY_HANDLE_FILE_INFORMATION fi;
+    ok = GetFileInformationByHandle (h, &fi);
+    if (ok)
+      {
+       identity->device = fi.dwVolumeSerialNumber;
+       identity->inode = fi.nFileIndexHigh;
+       identity->inode <<= (sizeof fi.nFileIndexLow) * CHAR_BIT;
+       identity->inode |= fi.nFileIndexLow;
+       identity->name = 0;
+      }
+    CloseHandle (h);
+  }
+
+  if (!ok)
+    {
+      identity->device = 0;
+      identity->inode = 0;
+
+      size_t bufsize;
+      size_t pathlen = 255;
+      char *cname = NULL;
+      do 
+      {
+       bufsize = pathlen;
+       cname = xrealloc (cname, bufsize);
+       pathlen = GetFullPathName (file_name, bufsize, cname, NULL);
+      }
+      while (pathlen > bufsize);
+      identity->name = xstrdup (cname);
+      free (cname);
+      str_lowercase (identity->name);
+    }
 #endif /* Windows */
 
   return identity;