13 /* The currently mounted filesystem */
14 __export
struct fs_info
*this_fs
= NULL
; /* Root filesystem */
16 /* Actual file structures (we don't have malloc yet...) */
17 __export
struct file files
[MAX_OPEN
];
19 /* Symlink hard limits */
20 #define MAX_SYMLINK_CNT 20
21 #define MAX_SYMLINK_BUF 4096
24 * Get a new inode structure
26 struct inode
*alloc_inode(struct fs_info
*fs
, uint32_t ino
, size_t data
)
28 struct inode
*inode
= zalloc(sizeof(struct inode
) + data
);
38 * Free a refcounted inode
40 void put_inode(struct inode
*inode
)
43 struct inode
*dead
= inode
;
44 int refcnt
= --(dead
->refcnt
);
45 dprintf("put_inode %p name %s refcnt %u\n", dead
, dead
->name
, refcnt
);
47 break; /* We still have references */
50 free((char *)dead
->name
);
56 * Get an empty file structure
58 static struct file
*alloc_file(void)
61 struct file
*file
= files
;
63 for (i
= 0; i
< MAX_OPEN
; i
++) {
73 * Close and free a file structure
75 static inline void free_file(struct file
*file
)
77 memset(file
, 0, sizeof *file
);
80 __export
void _close_file(struct file
*file
)
83 file
->fs
->fs_ops
->close_file(file
);
88 * Find and open the configuration file
90 __export
int open_config(void)
95 fd
= opendev(&__file_dev
, NULL
, O_RDONLY
);
99 fp
= &__file_info
[fd
];
101 handle
= this_fs
->fs_ops
->open_config(&fp
->i
.fd
);
114 __export
void mangle_name(char *dst
, const char *src
)
116 this_fs
->fs_ops
->mangle_name(dst
, src
);
119 size_t pmapi_read_file(uint16_t *handle
, void *buf
, size_t sectors
)
125 file
= handle_to_file(*handle
);
126 bytes_read
= file
->fs
->fs_ops
->getfssec(file
, buf
, sectors
, &have_more
);
129 * If we reach EOF, the filesystem driver will have already closed
130 * the underlying file... this really should be cleaner.
140 int searchdir(const char *name
, int flags
)
142 static char root_name
[] = "/";
144 char *path
, *inode_name
, *next_inode_name
;
145 struct inode
*tmp
, *inode
= NULL
;
146 int symlink_count
= MAX_SYMLINK_CNT
;
148 dprintf("searchdir: %s root: %p cwd: %p\n",
149 name
, this_fs
->root
, this_fs
->cwd
);
151 if (!(file
= alloc_file()))
155 /* if we have ->searchdir method, call it */
156 if (file
->fs
->fs_ops
->searchdir
) {
157 file
->fs
->fs_ops
->searchdir(name
, flags
, file
);
160 return file_to_handle(file
);
165 /* else, try the generic-path-lookup method */
170 dprintf("searchdir: Couldn't copy path\n");
174 /* Work with the current directory, by default */
175 inode
= get_inode(this_fs
->cwd
);
177 dprintf("searchdir: Couldn't use current directory\n");
181 for (inode_name
= path
; inode_name
; inode_name
= next_inode_name
) {
182 /* Root directory? */
183 if (inode_name
[0] == '/') {
184 next_inode_name
= inode_name
+ 1;
185 inode_name
= root_name
;
187 /* Find the next inode name */
188 next_inode_name
= strchr(inode_name
+ 1, '/');
189 if (next_inode_name
) {
190 /* Terminate the current inode name and point to next */
191 *next_inode_name
++ = '\0';
194 if (next_inode_name
) {
195 /* Advance beyond redundant slashes */
196 while (*next_inode_name
== '/')
199 /* Check if we're at the end */
200 if (*next_inode_name
== '\0')
201 next_inode_name
= NULL
;
203 dprintf("searchdir: inode_name: %s\n", inode_name
);
205 dprintf("searchdir: Remaining: %s\n", next_inode_name
);
207 /* Root directory? */
208 if (inode_name
[0] == '/') {
209 /* Release any chain that's already been established */
211 inode
= get_inode(this_fs
->root
);
215 /* Current directory? */
216 if (!strncmp(inode_name
, ".", sizeof "."))
219 /* Parent directory? */
220 if (!strncmp(inode_name
, "..", sizeof "..")) {
221 /* If there is no parent, just ignore it */
225 /* Add a reference to the parent so we can release the child */
226 tmp
= get_inode(inode
->parent
);
228 /* Releasing the child will drop the parent back down to 1 */
237 inode
= this_fs
->fs_ops
->iget(inode_name
, inode
);
239 /* Failure. Release the chain */
245 if (inode
->parent
&& inode
->parent
!= tmp
) {
246 dprintf("searchdir: iget returned a different parent\n");
253 inode
->name
= strdup(inode_name
);
254 dprintf("searchdir: path component: %s\n", inode
->name
);
256 /* Symlink handling */
257 if (inode
->mode
== DT_LNK
) {
261 /* target path + NUL */
262 new_len
= inode
->size
+ 1;
264 if (next_inode_name
) {
265 /* target path + slash + remaining + NUL */
266 new_len
+= strlen(next_inode_name
) + 1;
269 if (!this_fs
->fs_ops
->readlink
||
271 --symlink_count
== 0 ||
272 new_len
> MAX_SYMLINK_BUF
)
275 new_path
= malloc(new_len
);
279 copied
= this_fs
->fs_ops
->readlink(inode
, new_path
);
282 new_path
[copied
] = '\0';
283 dprintf("searchdir: Symlink: %s\n", new_path
);
285 if (next_inode_name
) {
286 new_path
[copied
] = '/';
287 strcpy(new_path
+ copied
+ 1, next_inode_name
);
288 dprintf("searchdir: New path: %s\n", new_path
);
292 path
= next_inode_name
= new_path
;
294 /* Add a reference to the parent so we can release the child */
295 tmp
= get_inode(inode
->parent
);
297 /* Releasing the child will drop the parent back down to 1 */
311 /* If there's more to process, this should be a directory */
312 if (next_inode_name
&& inode
->mode
!= DT_DIR
) {
313 dprintf("searchdir: Expected a directory\n");
323 dprintf("searchdir: Not found\n");
330 return file_to_handle(file
);
338 __export
int open_file(const char *name
, int flags
, struct com32_filedata
*filedata
)
342 char mangled_name
[FILENAME_MAX
];
344 dprintf("open_file %s\n", name
);
346 mangle_name(mangled_name
, name
);
347 rv
= searchdir(mangled_name
, flags
);
352 file
= handle_to_file(rv
);
354 if (file
->inode
->mode
!= DT_REG
) {
359 filedata
->size
= file
->inode
->size
;
360 filedata
->blocklg2
= SECTOR_SHIFT(file
->fs
);
361 filedata
->handle
= rv
;
366 __export
void close_file(uint16_t handle
)
371 file
= handle_to_file(handle
);
378 * initialize the memory management function;
379 * set up the vfs fs structure;
380 * initialize the device structure;
381 * invoke the fs-specific init function;
382 * initialize the cache if we need one;
383 * finally, get the current inode for relative path looking.
385 __bss16
uint16_t SectorSize
, SectorShift
;
387 void fs_init(com32sys_t
*regs
)
389 static struct fs_info fs
; /* The actual filesystem buffer */
390 uint8_t disk_devno
= regs
->edx
.b
[0];
391 uint8_t disk_cdrom
= regs
->edx
.b
[1];
392 sector_t disk_offset
= regs
->ecx
.l
| ((sector_t
)regs
->ebx
.l
<< 32);
393 uint16_t disk_heads
= regs
->esi
.w
[0];
394 uint16_t disk_sectors
= regs
->edi
.w
[0];
395 uint32_t maxtransfer
= regs
->ebp
.l
;
397 struct device
*dev
= NULL
;
398 /* ops is a ptr list for several fs_ops */
399 const struct fs_ops
**ops
= (const struct fs_ops
**)regs
->eax
.l
;
401 /* Default name for the root directory */
402 fs
.cwd_name
[0] = '/';
404 while ((blk_shift
< 0) && *ops
) {
405 /* set up the fs stucture */
409 * This boldly assumes that we don't mix FS_NODEV filesystems
410 * with FS_DEV filesystems...
412 if (fs
.fs_ops
->fs_flags
& FS_NODEV
) {
416 dev
= device_init(disk_devno
, disk_cdrom
, disk_offset
,
417 disk_heads
, disk_sectors
, maxtransfer
);
420 /* invoke the fs-specific init code */
421 blk_shift
= fs
.fs_ops
->fs_init(&fs
);
425 printf("No valid file system found!\n");
431 /* initialize the cache */
432 if (fs
.fs_dev
&& fs
.fs_dev
->cache_data
)
433 cache_init(fs
.fs_dev
, blk_shift
);
435 /* start out in the root directory */
436 if (fs
.fs_ops
->iget_root
) {
437 fs
.root
= fs
.fs_ops
->iget_root(&fs
);
438 fs
.cwd
= get_inode(fs
.root
);
439 dprintf("init: root inode %p, cwd inode %p\n", fs
.root
, fs
.cwd
);
442 if (fs
.fs_ops
->chdir_start
) {
443 if (fs
.fs_ops
->chdir_start() < 0)
444 printf("Failed to chdir to start directory\n");
447 SectorShift
= fs
.sector_shift
;
448 SectorSize
= fs
.sector_size
;