14 /* The currently mounted filesystem */
15 __export
struct fs_info
*this_fs
= NULL
; /* Root filesystem */
17 /* Actual file structures (we don't have malloc yet...) */
18 __export
struct file files
[MAX_OPEN
];
20 /* Symlink hard limits */
21 #define MAX_SYMLINK_CNT 20
22 #define MAX_SYMLINK_BUF 4096
25 * Get a new inode structure
27 struct inode
*alloc_inode(struct fs_info
*fs
, uint32_t ino
, size_t data
)
29 struct inode
*inode
= zalloc(sizeof(struct inode
) + data
);
39 * Free a refcounted inode
41 void put_inode(struct inode
*inode
)
44 struct inode
*dead
= inode
;
45 int refcnt
= --(dead
->refcnt
);
46 dprintf("put_inode %p name %s refcnt %u\n", dead
, dead
->name
, refcnt
);
48 break; /* We still have references */
51 free((char *)dead
->name
);
57 * Get an empty file structure
59 static struct file
*alloc_file(void)
62 struct file
*file
= files
;
64 for (i
= 0; i
< MAX_OPEN
; i
++) {
74 * Close and free a file structure
76 static inline void free_file(struct file
*file
)
78 memset(file
, 0, sizeof *file
);
81 __export
void _close_file(struct file
*file
)
84 file
->fs
->fs_ops
->close_file(file
);
89 * Find and open the configuration file
91 __export
int open_config(void)
96 fd
= opendev(&__file_dev
, NULL
, O_RDONLY
);
100 fp
= &__file_info
[fd
];
102 handle
= this_fs
->fs_ops
->open_config(&fp
->i
.fd
);
115 __export
void mangle_name(char *dst
, const char *src
)
117 this_fs
->fs_ops
->mangle_name(dst
, src
);
120 size_t pmapi_read_file(uint16_t *handle
, void *buf
, size_t sectors
)
126 file
= handle_to_file(*handle
);
127 bytes_read
= file
->fs
->fs_ops
->getfssec(file
, buf
, sectors
, &have_more
);
130 * If we reach EOF, the filesystem driver will have already closed
131 * the underlying file... this really should be cleaner.
141 int searchdir(const char *name
)
143 static char root_name
[] = "/";
145 char *path
, *inode_name
, *next_inode_name
;
146 struct inode
*tmp
, *inode
= NULL
;
147 int symlink_count
= MAX_SYMLINK_CNT
;
149 dprintf("searchdir: %s root: %p cwd: %p\n",
150 name
, this_fs
->root
, this_fs
->cwd
);
152 if (!(file
= alloc_file()))
156 /* if we have ->searchdir method, call it */
157 if (file
->fs
->fs_ops
->searchdir
) {
158 file
->fs
->fs_ops
->searchdir(name
, file
);
161 return file_to_handle(file
);
166 /* else, try the generic-path-lookup method */
171 dprintf("searchdir: Couldn't copy path\n");
175 /* Work with the current directory, by default */
176 inode
= get_inode(this_fs
->cwd
);
178 dprintf("searchdir: Couldn't use current directory\n");
182 for (inode_name
= path
; inode_name
; inode_name
= next_inode_name
) {
183 /* Root directory? */
184 if (inode_name
[0] == '/') {
185 next_inode_name
= inode_name
+ 1;
186 inode_name
= root_name
;
188 /* Find the next inode name */
189 next_inode_name
= strchr(inode_name
+ 1, '/');
190 if (next_inode_name
) {
191 /* Terminate the current inode name and point to next */
192 *next_inode_name
++ = '\0';
195 if (next_inode_name
) {
196 /* Advance beyond redundant slashes */
197 while (*next_inode_name
== '/')
200 /* Check if we're at the end */
201 if (*next_inode_name
== '\0')
202 next_inode_name
= NULL
;
204 dprintf("searchdir: inode_name: %s\n", inode_name
);
206 dprintf("searchdir: Remaining: %s\n", next_inode_name
);
208 /* Root directory? */
209 if (inode_name
[0] == '/') {
210 /* Release any chain that's already been established */
212 inode
= get_inode(this_fs
->root
);
216 /* Current directory? */
217 if (!strncmp(inode_name
, ".", sizeof "."))
220 /* Parent directory? */
221 if (!strncmp(inode_name
, "..", sizeof "..")) {
222 /* If there is no parent, just ignore it */
226 /* Add a reference to the parent so we can release the child */
227 tmp
= get_inode(inode
->parent
);
229 /* Releasing the child will drop the parent back down to 1 */
238 inode
= this_fs
->fs_ops
->iget(inode_name
, inode
);
240 /* Failure. Release the chain */
246 if (inode
->parent
&& inode
->parent
!= tmp
) {
247 dprintf("searchdir: iget returned a different parent\n");
254 inode
->name
= strdup(inode_name
);
255 dprintf("searchdir: path component: %s\n", inode
->name
);
257 /* Symlink handling */
258 if (inode
->mode
== DT_LNK
) {
262 /* target path + NUL */
263 new_len
= inode
->size
+ 1;
265 if (next_inode_name
) {
266 /* target path + slash + remaining + NUL */
267 new_len
+= strlen(next_inode_name
) + 1;
270 if (!this_fs
->fs_ops
->readlink
||
272 --symlink_count
== 0 ||
273 new_len
> MAX_SYMLINK_BUF
)
276 new_path
= malloc(new_len
);
280 copied
= this_fs
->fs_ops
->readlink(inode
, new_path
);
283 new_path
[copied
] = '\0';
284 dprintf("searchdir: Symlink: %s\n", new_path
);
286 if (next_inode_name
) {
287 new_path
[copied
] = '/';
288 strcpy(new_path
+ copied
+ 1, next_inode_name
);
289 dprintf("searchdir: New path: %s\n", new_path
);
293 path
= next_inode_name
= new_path
;
295 /* Add a reference to the parent so we can release the child */
296 tmp
= get_inode(inode
->parent
);
298 /* Releasing the child will drop the parent back down to 1 */
312 /* If there's more to process, this should be a directory */
313 if (next_inode_name
&& inode
->mode
!= DT_DIR
) {
314 dprintf("searchdir: Expected a directory\n");
324 dprintf("searchdir: Not found\n");
331 return file_to_handle(file
);
339 __export
int open_file(const char *name
, struct com32_filedata
*filedata
)
343 char mangled_name
[FILENAME_MAX
];
345 dprintf("open_file %s\n", name
);
347 mangle_name(mangled_name
, name
);
348 rv
= searchdir(mangled_name
);
353 file
= handle_to_file(rv
);
355 if (file
->inode
->mode
!= DT_REG
) {
360 filedata
->size
= file
->inode
->size
;
361 filedata
->blocklg2
= SECTOR_SHIFT(file
->fs
);
362 filedata
->handle
= rv
;
367 __export
void close_file(uint16_t handle
)
372 file
= handle_to_file(handle
);
379 * initialize the memory management function;
380 * set up the vfs fs structure;
381 * initialize the device structure;
382 * invoke the fs-specific init function;
383 * initialize the cache if we need one;
384 * finally, get the current inode for relative path looking.
386 __bss16
uint16_t SectorSize
, SectorShift
;
388 void fs_init(com32sys_t
*regs
)
390 static struct fs_info fs
; /* The actual filesystem buffer */
391 uint8_t disk_devno
= regs
->edx
.b
[0];
392 uint8_t disk_cdrom
= regs
->edx
.b
[1];
393 sector_t disk_offset
= regs
->ecx
.l
| ((sector_t
)regs
->ebx
.l
<< 32);
394 uint16_t disk_heads
= regs
->esi
.w
[0];
395 uint16_t disk_sectors
= regs
->edi
.w
[0];
396 uint32_t maxtransfer
= regs
->ebp
.l
;
398 struct device
*dev
= NULL
;
399 /* ops is a ptr list for several fs_ops */
400 const struct fs_ops
**ops
= (const struct fs_ops
**)regs
->eax
.l
;
402 /* Initialize malloc() */
405 /* Default name for the root directory */
406 fs
.cwd_name
[0] = '/';
408 while ((blk_shift
< 0) && *ops
) {
409 /* set up the fs stucture */
413 * This boldly assumes that we don't mix FS_NODEV filesystems
414 * with FS_DEV filesystems...
416 if (fs
.fs_ops
->fs_flags
& FS_NODEV
) {
420 dev
= device_init(disk_devno
, disk_cdrom
, disk_offset
,
421 disk_heads
, disk_sectors
, maxtransfer
);
424 /* invoke the fs-specific init code */
425 blk_shift
= fs
.fs_ops
->fs_init(&fs
);
429 printf("No valid file system found!\n");
435 /* initialize the cache */
436 if (fs
.fs_dev
&& fs
.fs_dev
->cache_data
)
437 cache_init(fs
.fs_dev
, blk_shift
);
439 /* start out in the root directory */
440 if (fs
.fs_ops
->iget_root
) {
441 fs
.root
= fs
.fs_ops
->iget_root(&fs
);
442 fs
.cwd
= get_inode(fs
.root
);
443 dprintf("init: root inode %p, cwd inode %p\n", fs
.root
, fs
.cwd
);
446 if (fs
.fs_ops
->chdir_start
) {
447 if (fs
.fs_ops
->chdir_start() < 0)
448 printf("Failed to chdir to start directory\n");
451 SectorShift
= fs
.sector_shift
;
452 SectorSize
= fs
.sector_size
;