summaryrefslogtreecommitdiff
path: root/fs/mount.c
blob: a54fb922e1b20a8364c3c89d32839143f5ea4c9f (plain)
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
#include <stddef.h>

#include "kernel.h"
#include "mount.h"

#include "log.h"

#include "lib/string/string.h"
#include "lib/printf/printf.h"

#include "fd.h"

static mount mounts[MAX_MOUNTS];
static uint32_t mounts_count=0;

char *mount_type_to_str(uint32_t t)
{
    switch(t)
    {
	case MOUNT_TYPE_EXT2:  return "EXT2";
//	case MOUNT_TYPE_PIPES: return "PIPES";
	case MOUNT_TYPE_SYS:   return "SYSFS";
    }
    return "UNKNOWN";
}

void mount_add(mount mnt)
{
    if(mounts_count==MAX_MOUNTS)kpanic("maxium number of mounts exceeded. increase MAX_MOUNTS in kernel.h and recomplie kernel.");
    mounts[mounts_count++]=mnt;
    klog("Mounted %s at %s",mount_type_to_str(mnt.type),mnt.path);
}

void mount_sysfs(ringbuffer *r, void (*f)(ringbuffer *r,char *fmt, ...))
{
    for(int i=0;i<mounts_count;i++)
    {
	mount *m=&mounts[i];
	f(r,"%s at %s",mount_type_to_str(m->type),m->path);
    }
}

static uint32_t check_match(char *p1, char *p2)
{
    uint32_t c=0;
    while(1)
    {
	if(*p1==0||*p2==0||*p1!=*p2)return c;
	c++;
	p1++;
	p2++;
        if(*p1=='/')return c;
    }
}

/** 
 *  Find the mountpoint correspoding with the given path and return in _mnt_ parameter.
 *  The return value points to the input path with chopped of prefix indicating the mount itself. 
 *  returns 0 if mount not found.
 */
static char* get_mount_for_path(char *path,mount *mnt)
{

    // start with root as default
    uint32_t best=0;
    uint32_t best_len=1;
    
    if(path[0]!='/'){
        kpanic("this works only for absolute paths! supplied: %s",path);
    }
    
    for(int i=0;i<mounts_count;i++)
    {
	mount *m=&mounts[i];
	uint32_t len=check_match(path+1,(m->path)+1);

	if(len>best_len&&path[len-1]=='/')//&&len==strlen(m->path))
	{
	    best=i;
	    best_len=len;
	}
    }

    *mnt=mounts[best];
    return path+best_len-1;
}

fd mount_file_open(char *path)
{
    mount m;
    char buf[256];
    if(path[0]!='/'){

        // we extract the PWD env variable!
        // TODO:  this is ugly!
        char **env1=VMEM_USER_ENV+1024*2;

        int i=0;
        while(1)
        {
            if(env1[i]==0)kpanic("unable to extract PWD!");
            if(!strcmp_l("PWD=",env1[i],4))
            {        
                sprintf(buf,"%s/%s",env1[i]+4,path);
                klog("absolute path exracted: %s",buf);
                break;
            }
            i++;
        }
        

    }
    else
    {
        sprintf(buf,"%s",path);
    }

    char *p=get_mount_for_path(buf,&m);
    return m.mount_file_open(&m,p);
}

int mount_read_dir (char *path, struct dirent *dirs, uint32_t *pos)
{
    mount m;
    char *p=get_mount_for_path(path,&m);
    return m.mount_read_dir(&m,p,dirs,pos);
}