162 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <vfs.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <stddef.h>
 | 
						|
#include <mem.h>
 | 
						|
#include <string.h>
 | 
						|
#include <debug.h>
 | 
						|
 | 
						|
file_t *fs_get(file_t *file)
 | 
						|
{
 | 
						|
  if(!file)
 | 
						|
    file = kcalloc(1, sizeof(file_t));
 | 
						|
  file->refs += 1;
 | 
						|
  return file;
 | 
						|
}
 | 
						|
file_t *fs_put(file_t *file)
 | 
						|
{
 | 
						|
  if(!file)
 | 
						|
    return file;
 | 
						|
  file->refs -= 1;
 | 
						|
  if(!file->refs)
 | 
						|
  {
 | 
						|
    kfree(file);
 | 
						|
    file = 0;
 | 
						|
  }
 | 
						|
  return file;
 | 
						|
}
 | 
						|
 | 
						|
int fs_open(file_t *file, uint64_t flags)
 | 
						|
{
 | 
						|
  if(file && file->driver && file->driver->open)
 | 
						|
    return file->driver->open(file, flags);
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
int fs_close(file_t *file)
 | 
						|
{
 | 
						|
  if(file && file->driver && file->driver->close)
 | 
						|
    return file->driver->close(file);
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
size_t fs_read(file_t *file, void *buffer, size_t nbyte, size_t offset)
 | 
						|
{
 | 
						|
  if(file && file->driver && file->driver->read)
 | 
						|
    return file->driver->read(file, buffer, nbyte, offset);
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
size_t fs_write(file_t *file, void *buffer, size_t nbyte, size_t offset)
 | 
						|
{
 | 
						|
  if(file && file->driver && file->driver->write)
 | 
						|
    return file->driver->write(file, buffer, nbyte, offset);
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
int fs_readdir(file_t *dir, dirent_t *entry, uint64_t offset)
 | 
						|
{
 | 
						|
  if(dir && dir->driver && dir->driver->readdir)
 | 
						|
    return dir->driver->readdir(dir, entry, offset);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
file_t *fs_finddir(file_t *dir, char *name)
 | 
						|
{
 | 
						|
  dirent_t entry;
 | 
						|
  int offset = 0;
 | 
						|
  while(1)
 | 
						|
  {
 | 
						|
    int retval = fs_readdir(dir, &entry, offset++);
 | 
						|
    if(!retval)
 | 
						|
      break;
 | 
						|
    if(strcmp((&entry)->name, name))
 | 
						|
    {
 | 
						|
      fs_put(entry.file);
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    return entry.file;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void fs_mount(file_t *root, const char *path)
 | 
						|
{
 | 
						|
  struct mountpoint *mp = kcalloc(1, sizeof(struct mountpoint) + strlen(path) + 1);
 | 
						|
  mp->root = fs_get(root);
 | 
						|
  mp->path_len = strlen(path);
 | 
						|
  memcpy(mp->path, path, mp->path_len);
 | 
						|
  mp->path[mp->path_len] = '\0';
 | 
						|
  LIST_APPEND(mountpoints, mp, mountpoints);
 | 
						|
}
 | 
						|
 | 
						|
void fs_umount(const char *path)
 | 
						|
{
 | 
						|
  LIST_FOREACH(mountpoints, struct mountpoint, mp, mountpoints)
 | 
						|
  {
 | 
						|
    if(!strcmp(mp->path, path))
 | 
						|
    {
 | 
						|
      LIST_REMOVE(mountpoints, mp, mountpoints);
 | 
						|
      fs_put(mp->root);
 | 
						|
      kfree(mp);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
struct mountpoint *fs_closest_mp(const char *path)
 | 
						|
{
 | 
						|
  uint64_t best_len = 0;
 | 
						|
  struct mountpoint *best = 0;
 | 
						|
  LIST_FOREACH(mountpoints, struct mountpoint, mp, mountpoints)
 | 
						|
  {
 | 
						|
    uint64_t len = mp->path_len;
 | 
						|
    if((!strncmp(mp->path, path, len-1)) && (len > best_len))
 | 
						|
    {
 | 
						|
      best = mp;
 | 
						|
      best_len = len;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return best;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
char *pathtok(char **p)
 | 
						|
{
 | 
						|
  char sep = '/';
 | 
						|
 | 
						|
  if(!**p) return 0;
 | 
						|
 | 
						|
  while(**p && **p == sep) (*p)++;
 | 
						|
  char *ret = *p;
 | 
						|
  while(**p && **p != sep) (*p)++;
 | 
						|
  if(**p) **p = '\0', (*p)++;
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
file_t *fs_namef(const char *path)
 | 
						|
{
 | 
						|
  char *name;
 | 
						|
  char *p = strdup(path);
 | 
						|
  char *q = p;
 | 
						|
  struct mountpoint *mp = fs_closest_mp(path);
 | 
						|
  file_t *root = mp->root;
 | 
						|
  p += mp->path_len;
 | 
						|
  file_t *dir = fs_get(root);
 | 
						|
 | 
						|
  while((name = pathtok(&p)))
 | 
						|
  {
 | 
						|
    file_t *next = fs_finddir(dir, name);
 | 
						|
    if(!next)
 | 
						|
    {
 | 
						|
      dir =  0;
 | 
						|
      goto end;
 | 
						|
    }
 | 
						|
    fs_put(dir);
 | 
						|
    dir = next;
 | 
						|
  }
 | 
						|
end:
 | 
						|
  kfree(q);
 | 
						|
  return dir;
 | 
						|
}
 |