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;
}
|