1 #include <stdlib.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <sys/stat.h>
6
7 #include "bosmeta.h"
8 #include "dosdir.h"
9
10 #if 0
11 #include "nfd.h"
12 #define TRACE(x) NFD(x)
13 #define DEBUG(x) NFD(x)
14 #else
15 #define TRACE(x)
16 #define DEBUG(x)
17 #endif
18
19
20 /* x:\dev\phys folder lists respectively */
21 LIST root;
22
23 static LIST root_dev;
24 static LIST root_dev_phys;
25
26 /* cookie release/dup */
27 static
28 void release_cookie( FCOOKIE *fc);
29
30 static
release_folder(LIST * f)31 void release_folder( LIST *f) {
32 LINKABLE *fc = listFirst(f);
33 while (fc) {
34 FCOOKIE *trash = (FCOOKIE*)fc;
35 fc = listNext(fc);
36 release_cookie( trash);
37 }
38 }
39
40 static
release_cookie(FCOOKIE * fc)41 void release_cookie( FCOOKIE *fc) {
42 release_folder( fc->folder);
43 free( fc->name);
44 free( fc);
45 }
46
47 static
dup_cookie(FCOOKIE * s)48 FCOOKIE *dup_cookie( FCOOKIE *s) {
49 FCOOKIE *fc;
50 fc = malloc(sizeof(FCOOKIE));
51 fc->name = strdup(s->name);
52 fc->attr = s->attr;
53 fc->folder = s->folder;
54 fc->bos_dev = s->bos_dev;
55 fc->bos_info_flags = s->bos_info_flags;
56 return fc;
57 }
58
bosfs_initialize(void)59 long bosfs_initialize(void) {
60 int i;
61 metainit_t metainit={0,0,0,0};
62 FCOOKIE *fc;
63
64 Metainit(&metainit);
65 TRACE(("MetaDOS version=%s, drives=%x\n", metainit.version, metainit.drives_map));
66 if (metainit.version == NULL) {
67 DEBUG(("MetaDOS not installed\n"));
68 return -1;
69 }
70
71 if (metainit.drives_map == 0) {
72 DEBUG(("No MetaDOS devices present\n"));
73 return -1;
74 }
75
76 listInit( &root);
77
78 { /* create the x:\dev folder */
79 fc = malloc(sizeof(FCOOKIE));
80 fc->name = strdup("dev");
81 fc->attr = FA_DIR;
82 fc->folder = &root_dev;
83 fc->bos_dev = 0;
84
85 /* add it to the folder */
86 listInsert( root.head.next, (LINKABLE*)fc);
87 }
88
89 listInit( &root_dev);
90
91 { /* create the x:\dev\phys folder */
92 fc = malloc(sizeof(FCOOKIE));
93 fc->name = strdup("bos");
94 fc->attr = FA_DIR;
95 fc->folder = &root_dev_phys;
96 fc->bos_dev = 0;
97
98 /* add it to the folder */
99 listInsert( root_dev.head.next, (LINKABLE*)fc);
100 }
101
102 listInit( &root_dev_phys);
103
104 for (i='A'; i<='Z'; i++) if (metainit.drives_map & (1<<(i-'A'))) {
105 metaopen_t metaopen;
106 int handle;
107 char name[] = "A";
108 name[0] = i;
109
110 fc = malloc(sizeof(FCOOKIE));
111 fc->name = strdup(name);
112 fc->attr = 0;
113 fc->folder = NULL;
114 fc->bos_dev = i;
115 fc->bos_info_flags = BOS_INFO_DEVHIDDEN; /* by default hide from U:\dev */
116
117 DEBUG(("dev: %s->%s\n", name, fc->name));
118
119 /* attempt to get the bos_info */
120 handle = Metaopen(i, &metaopen);
121 if (handle == 0) {
122 bos_info_t info;
123 if ( ! Metaioctl(i, METADOS_IOCTL_MAGIC, METADOS_IOCTL_BOSINFO, &info)) {
124 DEBUG(("ioctl: %s->%s %lx\n", name, fc->name, info.flags));
125 fc->bos_info_flags = info.flags;
126 }
127 Metaclose(i);
128
129 DEBUG(("dev: %s->%s %lx\n", name, fc->name, fc->bos_info_flags));
130
131 /* the BOSINFO states that the device should not be visible
132 * in x:\dev\bos nor in x:\dev\bos */
133 if ( fc->bos_info_flags & BOS_INFO_BOSHIDDEN ) {
134 release_cookie( fc );
135 continue;
136 }
137
138 /* insert the devices that have a decent name also to u:\dev */
139 if ( ! (fc->bos_info_flags & BOS_INFO_DEVHIDDEN) && *metaopen.name ) {
140 FCOOKIE *cfc = dup_cookie(fc);
141 free( cfc->name);
142 cfc->name = strdup(metaopen.name);
143 listInsert( &root_dev.tail, (LINKABLE*)cfc);
144 }
145 }
146
147 /* add it to the folder */
148 listInsert( root_dev_phys.head.next, (LINKABLE*)fc);
149 }
150
151 return 0;
152 }
153
154
155 long
getxattr(FCOOKIE * fc,struct xattr * res)156 getxattr (FCOOKIE *fc, struct xattr *res)
157 {
158 res->mode = 0666;
159 res->mode |= fc->attr & FA_DIR ? (S_IFDIR|0111) : 0;
160
161 res->index = (long)fc;
162 res->dev = (long)&root;
163 res->rdev = (long)&root;
164 res->nlink = 1;
165 res->uid = 0;
166 res->gid = 0;
167 res->size = 0;
168 res->blksize = 512;
169 res->nblocks = ( res->size + res->blksize - 1) >> 9;
170 // FIXME!
171 res->mtime = 0;
172 res->mdate = 0;
173 res->atime = 0;
174 res->adate = 0;
175 res->ctime = 0;
176 res->cdate = 0;
177 res->attr = fc->attr;
178 res->reserved2 = 0;
179 res->reserved3[0] = 0;
180 res->reserved3[1] = 0;
181 return 0;
182 }
183
184
185 long
name2cookie(LIST * folder,const char * name,FCOOKIE ** res)186 name2cookie (LIST *folder, const char *name, FCOOKIE **res)
187 {
188 char lowname[32];
189 FCOOKIE* fc;
190
191 DEBUG(( "name2cookie: name=%s\n", name));
192
193 /* look for 'name' in the folder */
194 listForEach( FCOOKIE*, fc, folder) {
195 char *c = lowname;
196 char *f = fc->name;
197 while ( (*c++ = tolower(*f++)) ) ;
198
199 DEBUG(( "name2cookie: fc->name=%s\n", fc->name));
200 if ( ! strcmp( lowname, name) ) {
201 *res = fc;
202 return 0;
203 }
204 }
205
206 return -ENOENT;
207 }
208
209 /*
210 * routines for parsing path names
211 */
212
213 /*
214 * relpath2cookie converts a TOS file name into a file cookie representing
215 * the directory the file resides in, and a character string representing
216 * the name of the file in that directory. The character string is
217 * copied into the "lastname" array. If lastname is NULL, then the cookie
218 * returned actually represents the file, instead of just the directory
219 * the file is in.
220 *
221 * note that lastname, if non-null, should be big enough to contain all the
222 * characters in "path", since if the file system doesn't want the kernel
223 * to do path name parsing we may end up just copying path to lastname
224 * and returning the current or root directory, as appropriate
225 *
226 * "dir" is the directory relative to which the search should start.
227 * if you just want the current directory, use path2cookie instead.
228 *
229 */
230
231 # define DIRSEP(p) (((p) == '\\') || ((p) == '/'))
232
233 long
relpath2cookie(FCOOKIE * dir,const char * path,char * lastname,FCOOKIE ** res)234 relpath2cookie (FCOOKIE *dir, const char *path, char *lastname, FCOOKIE **res)
235 {
236 long r = 0;
237 short do_last = (lastname == NULL);
238
239 char temp[PATH_MAX];
240 if ( ! lastname ) lastname = temp;
241
242 DEBUG(( "relpath2cookie: dir=%s path=%s\n", dir->name, path));
243
244 /* first, check for a drive letter
245 */
246 if (path[1] == ':')
247 {
248 char c = tolower ((int)path[0] & 0xff);
249 if (c >= 'a' && c <= 'z')
250 path += 2;
251 else if (c >= '1' && c <= '6')
252 path += 2;
253 }
254
255 while (*path)
256 {
257 /* now we must have a directory, since there are more things
258 * in the path
259 */
260 if ( ! (dir->attr & FA_DIR) )
261 return -ENOTDIR;
262
263 /* skip slashes
264 */
265 while (DIRSEP (*path))
266 path++;
267
268 /* if there's nothing left in the path, we can break here
269 */
270 if (!*path)
271 {
272 *res = dir;
273 *lastname = '\0';
274 return 0;
275 }
276
277 /* next, peel off the next name in the path
278 */
279 {
280 register int len;
281 register char c, *s;
282
283 len = 0;
284 s = lastname;
285 c = *path;
286 while (c && !DIRSEP (c))
287 {
288 if (len++ < PATH_MAX)
289 *s++ = tolower(c);
290 c = *++path;
291 }
292
293 *s = 0;
294 }
295
296 /* if there are no more names in the path, and we don't want
297 * to actually look up the last name, then we're done
298 */
299 if (!do_last && !*path)
300 {
301 *res = dir;
302 return 0;
303 }
304
305 r = name2cookie (dir->folder, lastname, res);
306 if (r)
307 {
308 if (r == -ENOENT && *path)
309 {
310 /* the "file" we didn't find was treated as a directory */
311 return -ENOTDIR;
312 }
313 return r;
314 }
315
316 dir = *res;
317 }
318
319 return 0;
320 }
321
322 long
path2cookie(const char * path,char * lastname,FCOOKIE ** res)323 path2cookie (const char *path, char *lastname, FCOOKIE **res)
324 {
325 static FCOOKIE rootfc;
326 long r;
327
328 rootfc.name = "devdir:"; // FIXME: DEBUG!
329 rootfc.attr = FA_DIR;
330 rootfc.folder = &root;
331 rootfc.bos_dev = 0;
332 r = relpath2cookie ( &rootfc, path, lastname, res);
333 DEBUG(( "path2cookie: r=%d\n", r));
334 return r;
335 }
336
337
338