Welcome to mirror list, hosted at ThFree Co, Russian Federation.

stat.c « go32 « sys « libc « newlib - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e64e5b80c454e7735ec3e5d165d252ffe030a37d (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
/*
  (c) Copyright 1992 Eric Backus

  This software may be used freely so long as this copyright notice is
  left intact.  There is no warrantee on this software.
*/

#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>

#include "dos.h"
#include <errno.h>
#include <stdio.h>

extern int	_stat_assist(const char *, struct stat *);
extern void	_fixpath(const char *, char *);

struct path_list
{
    struct path_list	*next;
    char		*path;
    int			inode;
};

static int
fixinode(const char *path, struct stat *buf)
{
    static struct path_list	*path_list[1256];
    /* Start the inode count at three, since root path should be two */
    static int			inode_count = 3;

    struct path_list		*path_ptr, *prev_ptr;
    const char			*p;
    int				hash;

    /* Skip over device and leading '/' */
    if (path[1] == ':' && path[2] == '/') path += 3;

    /* We could probably use a better hash than this */
    p = path;
    hash = 0;
    while (*p != '\0') hash += *p++;
    hash = hash & 0xff;

    /* Have we seen this string? */
    path_ptr = path_list[hash];
    prev_ptr = path_ptr;
    while (path_ptr)
    {
	if (strcmp(path, path_ptr->path) == 0) break;
	prev_ptr = path_ptr;
	path_ptr = path_ptr->next;
    }

    if (path_ptr)
	/* Same string, so same inode */
	buf->st_ino = path_ptr->inode;
    else
    {
	/* New string with same hash code */
	path_ptr = malloc(sizeof *path_ptr);
	if (path_ptr == NULL)
	  {
	    errno = ENOMEM;
	    return -1;
	  }
	path_ptr->next = NULL;
	path_ptr->path = strdup(path);
	if (path_ptr->path == NULL)
	  {
	    errno = ENOMEM;
	    return -1;
	  }
	path_ptr->inode = inode_count;
	if (prev_ptr)
	    prev_ptr->next = path_ptr;
	else
	    path_list[hash] = path_ptr;
	buf->st_ino = inode_count;
	inode_count++;
    }
    return 0;
}

int
stat(const char *path, struct stat *buf)
{
    static int	stat_called_before = 0;
    char	p[1090];	/* Should be p[PATH_MAX+1] */
    int		status;

    /* Normalize the path */
    _fixpath(path, p);

    /* Work around strange bug with stat and time */
    if (!stat_called_before)
    {
	stat_called_before = 1;
	(void) time((time_t *) 0);
    }

    /* Check for root path */
    if (strcmp(p, "/") == 0 || strcmp(p + 1, ":/") == 0)
    {
	/* Handle root path as special case, stat_assist doesn't like
	   the root directory. */
	if (p[1] == ':')
	{
	    if (p[0] >= 'a' && p[0] <= 'z')
		buf->st_dev = p[0] - 'a';
	    else
		buf->st_dev = p[0] - 'A';
	}
	else
	    buf->st_dev = -1;	/* No device? */
	buf->st_ino = 2;	/* Root path always inode 2 */
	buf->st_mode = S_IFDIR | S_IREAD | S_IWRITE | S_IEXEC;
	buf->st_nlink = 1;
	buf->st_uid = getuid();
	buf->st_gid = getgid();
	buf->st_rdev = buf->st_dev;
	buf->st_size = 0;
	buf->st_atime = 0;
	buf->st_mtime = 0;
	buf->st_ctime = 0;
	buf->st_blksize = 512;	/* Not always correct? */
	status = 0;
    }
    else
    {
	status = _stat_assist(p, buf);

	/* Make inode numbers unique */
	if (status == 0) status = fixinode(p, buf);

	/* The stat_assist does something weird with st_dev, but sets
	   st_rdev to the drive number.  Fix st_dev. */
	buf->st_dev = buf->st_rdev;

	/* Make all files owned by ourself. */
	buf->st_uid = getuid();
	buf->st_gid = getgid();

	/* Make all directories writable.  They always are in DOS, but
	   stat_assist doesn't think so. */
	if (S_ISDIR(buf->st_mode)) buf->st_mode |= S_IWRITE;
    }

    return status;
}