summaryrefslogtreecommitdiff
path: root/navit/support/libc/stat.c
blob: 586dcf714033f5b1d86f9ee1be2dca43b2758da7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 * stat.c: _stat, stat and fstat implementations for WinCE.
 *
 * This file has no copyright assigned and is placed in the Public Domain.
 * This file is a part of the mingw-runtime package.
 * No warranty is given; refer to the file DISCLAIMER within the package.
 *
 * Written by Pedro Alves <pedro_alves@portugalmail.pt> 10 Feb 2007
 *
 */

#include <windows.h>
#include <time.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <stdio.h>
#include "debug.h"

#include "timeutil.h"

struct stat_file_info_t
{
  DWORD dwFileAttributes;
  FILETIME ftLastWriteTime;
  FILETIME ftCreationTime;
  FILETIME ftLastAccessTime;
  DWORD nFileSizeLow;
};

#define COPY_MEMBER(DEST, SRC, MEMBER)		\
  do {						\
    (DEST)->MEMBER = (SRC)->MEMBER;		\
  } while (0)

#define TO_STAT_FILE_INFO(DEST, SRC)		\
  do {						\
    COPY_MEMBER (DEST, SRC, dwFileAttributes);	\
    COPY_MEMBER (DEST, SRC, ftLastWriteTime);	\
    COPY_MEMBER (DEST, SRC, ftCreationTime);	\
    COPY_MEMBER (DEST, SRC, ftLastAccessTime);	\
    COPY_MEMBER (DEST, SRC, nFileSizeLow);	\
  } while (0)

static int
__stat_by_file_info (struct stat_file_info_t *fi, struct _stat *st, int exec)
{
  int permission = _S_IREAD;

  memset (st, 0, sizeof (*st));

  st->st_size = fi->nFileSizeLow;
  st->st_mode = _S_IFREG;

  if((fi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
    st->st_mode = _S_IFDIR | _S_IEXEC;
  else if (exec)
    permission |= _S_IEXEC;

  if((fi->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
    permission |= _S_IWRITE;

  st->st_mode |= permission | (permission >> 3) | (permission >> 6);

  st->st_nlink = 1; /* always 1? */
  st->st_rdev = 1; /* Where to get drive info?  */
  st->st_ino = 0; /* always 0 on Windows */

  st->st_mtime = __FILETIME_to_time_t (&fi->ftLastWriteTime);
  st->st_ctime = __FILETIME_to_time_t (&fi->ftCreationTime);
  st->st_atime = __FILETIME_to_time_t (&fi->ftLastAccessTime);

  /* Looks like the code below is never triggered.
     Windows CE always only keeps the LastWriteTime, and
     copies it to the CreationTime and LastAccessTime fields.  */
  if (st->st_ctime == 0)
    st->st_ctime = st->st_mtime;
  if (st->st_atime == 0)
    {
      /* On XP, at least, the st_atime is always set to the same as
	 the st_mtime, except the hour/min/sec == 00:00:00.  */
      SYSTEMTIME s;
      FILETIME f = fi->ftLastWriteTime;
      FileTimeToSystemTime (&f, &s);
      s.wHour = 0; s.wMinute = 0;
      s.wSecond = 0; s.wMilliseconds = 0;
      SystemTimeToFileTime (&s, &f);
      st->st_atime = __FILETIME_to_time_t (&f);
      /* st->st_atime = st->st_mtime; */
    }
  return 0;
}

int
_fstat (int fd, struct _stat *st)
{
  BY_HANDLE_FILE_INFORMATION fi;
  struct stat_file_info_t sfi;

  if (!GetFileInformationByHandle ((HANDLE) fd, &fi))
    return -1;
  TO_STAT_FILE_INFO (&sfi, &fi);
  return __stat_by_file_info (&sfi, st, 0);
}

int
fstat (int fd, struct stat *st)
{
  return _fstat (fd, (struct _stat *)st);
}

int
_stat (const char *path, struct _stat *st)
{
  WIN32_FIND_DATAW fd;
  HANDLE h;
  int ret;
  struct stat_file_info_t sfi;
  wchar_t pathw[MAX_PATH + 1];
  size_t len;
  int exec;

	dbg(lvl_debug,"path=%s\n",path);
  mbstowcs (pathw, path, MAX_PATH);
	dbg(lvl_debug,"wide path=%S\n",pathw);
  if((h = FindFirstFileW (pathw, &fd)) == INVALID_HANDLE_VALUE)
    {
      DWORD dwError = GetLastError ();
	dbg(lvl_error,"no file\n");
      if(dwError == ERROR_NO_MORE_FILES)
	/* Convert error to something more sensible.  */
	SetLastError (ERROR_FILE_NOT_FOUND);
      return -1;
    }

  TO_STAT_FILE_INFO (&sfi, &fd);

  len = strlen (path);
  exec = (len >= 4
	  && strcasecmp (path + len - 4, ".exe") == 0);
  ret = __stat_by_file_info (&sfi, st, exec);
	dbg(lvl_debug,"ret=%d\n",ret);
  FindClose (h);
  return ret;
}

int
stat (const char *path, struct stat *st)
{
  return _stat (path, (struct _stat *)st);
}