dfs_fs.c 11.4 KB
Newer Older
1
/*
2 3 4 5 6 7 8 9 10 11 12 13 14
 * File      : dfs_fs.c
 * This file is part of Device File System in RT-Thread RTOS
 * COPYRIGHT (C) 2004-2010, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE.
 *
 * Change Logs:
 * Date           Author       Notes
 * 2005-02-22     Bernard      The first version.
 * 2010-06-30     Bernard      Optimize for RT-Thread RTOS
 */
15
#include <dfs_fs.h>
16 17
#include <dfs_file.h>

B
bernard.xiong@gmail.com 已提交
18 19 20 21 22
/**
 * @addtogroup FsApi
 */
/*@{*/

23 24 25 26 27 28 29 30
/**
 * this function will register a file system instance to device file system.
 *
 * @param ops the file system instance to be registered.
 *
 * @return 0 on sucessful, -1 on failed.
 */
int dfs_register(const struct dfs_filesystem_operation* ops)
31
{
32 33 34
    int index, result;

	result = 0;
35

36 37
	/* lock filesystem */
	dfs_lock();
38

wuyangyong's avatar
wuyangyong 已提交
39 40 41 42 43
    /* check if this filesystem was already registered */
    for (index = 0; index < DFS_FILESYSTEM_TYPES_MAX; index++)
    {
        if (filesystem_operation_table[index] != RT_NULL &&
                strcmp(filesystem_operation_table[index]->name, ops->name) == 0)
44 45
        {
        	result = -1;
wuyangyong's avatar
wuyangyong 已提交
46
            goto err;
47
        }
wuyangyong's avatar
wuyangyong 已提交
48
    }
49

wuyangyong's avatar
wuyangyong 已提交
50 51 52
    /* find out an empty filesystem type entry */
    for (index = 0; index < DFS_FILESYSTEM_TYPES_MAX && filesystem_operation_table[index] != RT_NULL;
            index++) ;
53

wuyangyong's avatar
wuyangyong 已提交
54
    /* filesystem type table full */
55 56 57 58 59
    if (index == DFS_FILESYSTEM_TYPES_MAX)
	{
		result = -1;
		goto err;
    }
60

wuyangyong's avatar
wuyangyong 已提交
61 62 63
    /* save the filesystem's operations */
    filesystem_operation_table[index] = ops;

64
err:
65 66
	dfs_unlock();
    return result;
67 68
}

69 70 71 72 73 74 75 76
/**
 * this function will return the file system mounted on specified path.
 *
 * @param path the specified path string.
 *
 * @return the found file system or NULL if no file system mounted on 
 * specified path
 */
77 78
struct dfs_filesystem* dfs_filesystem_lookup(const char *path)
{
wuyangyong's avatar
wuyangyong 已提交
79 80 81 82 83 84
    struct dfs_filesystem* fs;
    rt_uint32_t index, fspath, prefixlen;

    fs = RT_NULL;
    prefixlen = 0;

85 86
    /* lock filesystem */
	dfs_lock();
wuyangyong's avatar
wuyangyong 已提交
87 88 89 90 91 92 93 94

    /* lookup it in the filesystem table */
    for (index = 0; index < DFS_FILESYSTEMS_MAX + 1; index++)
    {
        fspath = strlen(filesystem_table[index].path);
        if (fspath < prefixlen) continue;

        if ((filesystem_table[index].ops != RT_NULL) &&
95
                strncmp(filesystem_table[index].path, path, fspath) == 0)
wuyangyong's avatar
wuyangyong 已提交
96 97 98 99 100 101
        {
            fs = &filesystem_table[index];
            prefixlen = fspath;
        }
    }

102 103
	dfs_unlock();

wuyangyong's avatar
wuyangyong 已提交
104
    return fs;
105 106
}

107 108 109 110 111 112 113 114 115
/**
 * this function will fetch the partition table on specified buffer.
 *
 * @param part the returned partition structure.
 * @param buf the buffer contains partition table.
 * @param pindex the index of partition table to fetch.
 *
 * @return RT_EOK on successful or -RT_ERROR on failed.
 */
116 117 118 119 120
rt_err_t dfs_filesystem_get_partition(struct dfs_partition* part, rt_uint8_t* buf, rt_uint32_t pindex)
{
#define DPT_ADDRESS		0x1be		/* device partition offset in Boot Sector */
#define DPT_ITEM_SIZE	16			/* partition item size */

wuyangyong's avatar
wuyangyong 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
    rt_uint8_t* dpt;
    rt_uint8_t type;
    rt_err_t result;

    RT_ASSERT(part != RT_NULL);
    RT_ASSERT(buf != RT_NULL);

    result = RT_EOK;

    dpt = buf + DPT_ADDRESS + pindex * DPT_ITEM_SIZE;

    if ((*dpt != 0x80) && (*dpt != 0x00))
    {
        /* which is not a partition table */
        result = -RT_ERROR;
        return result;
    }

    /* get partition type */
    type = *(dpt+4);

    if (type != 0)
    {
        /* set partition type */
        part->type = type;

        /* get partition offset and size */
        part->offset = *(dpt+ 8) | *(dpt+ 9) << 8 |
                       *(dpt+10) << 16 | *(dpt+11) << 24;
        part->size = *(dpt+12) | *(dpt+13) << 8 |
                     *(dpt+14) << 16 | *(dpt+15) << 24;
152

153
        rt_kprintf("found part[%d], begin: %d, size: ",
wuyangyong's avatar
wuyangyong 已提交
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
                   pindex, part->offset * 512);
        if ( (part->size>>11) > 0 ) /* MB */
        {
            unsigned int part_size;
            part_size = part->size>>11;/* MB */
            if ( (part_size>>10) > 0) /* GB */
            {
                rt_kprintf("%d.%d%s",part_size>>10,part_size&0x3FF,"GB\r\n");/* GB */
            }
            else
            {
                rt_kprintf("%d.%d%s",part_size,(part->size>>1)&0x3FF,"MB\r\n");/* MB */
            }
        }
        else
        {
            rt_kprintf("%d%s",part->size>>1,"KB\r\n");/* KB */
        }
    }
    else
    {
        result = -RT_ERROR;
    }
177

wuyangyong's avatar
wuyangyong 已提交
178
    return result;
179 180
}

181 182 183 184
/**
 * this function will mount a file system on a specified path.
 *
 * @param device_name the name of device which includes a file system.
B
bernard.xiong@gmail.com 已提交
185
 * @param path the path to mount a file system
186 187
 * @param filesystemtype the file system type
 * @param rwflag the read/write etc. flag.
B
bernard.xiong@gmail.com 已提交
188
 * @param data the private data(parameter) for this file system.
189 190 191
 *
 * @return 0 on successful or -1 on failed.
 */
192
int dfs_mount(const char* device_name, const char* path,
wuyangyong's avatar
wuyangyong 已提交
193 194
              const char* filesystemtype, unsigned long rwflag, const
              void* data)
195
{
196
    const struct dfs_filesystem_operation* ops;
wuyangyong's avatar
wuyangyong 已提交
197 198 199 200 201 202
    struct dfs_filesystem* fs;
    char *fullpath=RT_NULL;
    rt_device_t dev_id;
    int index;

    /* open specific device */
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
	if (device_name != RT_NULL)
	{
		dev_id = rt_device_find(device_name);
		if (dev_id == RT_NULL)
		{
			/* no this device */
			rt_set_errno(-DFS_STATUS_ENODEV);
			return -1;
		}
	}
	else
	{
		/* which is a non-device filesystem mount */
		dev_id = RT_NULL;
	}
wuyangyong's avatar
wuyangyong 已提交
218 219

    /* find out specific filesystem */
220
	dfs_lock();
wuyangyong's avatar
wuyangyong 已提交
221 222 223 224 225 226 227 228 229
    for ( index = 0; index < DFS_FILESYSTEM_TYPES_MAX; index++ )
    {
        if (strcmp(filesystem_operation_table[index]->name, filesystemtype) == 0)break;
    }

    /* can't find filesystem */
    if ( index == DFS_FILESYSTEM_TYPES_MAX )
    {
        rt_set_errno(-DFS_STATUS_ENODEV);
230
        dfs_unlock();
wuyangyong's avatar
wuyangyong 已提交
231 232 233
        return -1;
    }
    ops = filesystem_operation_table[index];
234
    dfs_unlock();
wuyangyong's avatar
wuyangyong 已提交
235 236

    /* make full path for special file */
237 238
	fullpath = dfs_normalize_path(RT_NULL, path);
    if ( fullpath == RT_NULL) /* not an abstract path */
wuyangyong's avatar
wuyangyong 已提交
239 240 241 242 243 244 245 246 247 248
    {
        rt_set_errno(-DFS_STATUS_ENOTDIR);
        return -1;
    }

    /* Check if the path exists or not, raw APIs call, fixme */
    if ( (strcmp(fullpath, "/") != 0) && (strcmp(fullpath, "/dev") != 0) )
    {
        struct dfs_fd fd;

249
        if ( dfs_file_open(&fd, fullpath, DFS_O_RDONLY | DFS_O_DIRECTORY) < 0 )
wuyangyong's avatar
wuyangyong 已提交
250
        {
251
        	rt_free(fullpath);
wuyangyong's avatar
wuyangyong 已提交
252 253 254
            rt_set_errno(-DFS_STATUS_ENOTDIR);
            return -1;
        }
255
        dfs_file_close(&fd);
wuyangyong's avatar
wuyangyong 已提交
256 257 258
    }

    /* check whether the file system mounted or not */
259
	dfs_lock();
wuyangyong's avatar
wuyangyong 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    for (index =0; index < DFS_FILESYSTEMS_MAX; index++)
    {
        if ( filesystem_table[index].ops != RT_NULL &&
                strcmp(filesystem_table[index].path, path) == 0 )
        {
            rt_set_errno(-DFS_STATUS_EINVAL);
            goto err1;
        }
    }

    /* find out en empty filesystem table entry */
    for (index = 0; index < DFS_FILESYSTEMS_MAX && filesystem_table[index].ops != RT_NULL;
            index++) ;
    if ( index == DFS_FILESYSTEMS_MAX )	/* can't find en empty filesystem table entry */
    {
275
        rt_set_errno(-DFS_STATUS_ENOSPC);
wuyangyong's avatar
wuyangyong 已提交
276 277 278 279 280
        goto err1;
    }

    /* register file system */
    fs = &(filesystem_table[index]);
281
	fs->path = fullpath;
wuyangyong's avatar
wuyangyong 已提交
282 283 284
    fs->ops = ops;
    fs->dev_id = dev_id;
    /* release filesystem_table lock */
285
	dfs_unlock();
wuyangyong's avatar
wuyangyong 已提交
286

287 288
	/* open device, but do not check the status of device */
	if (dev_id != RT_NULL) rt_device_open(fs->dev_id, RT_DEVICE_OFLAG_RDWR);
wuyangyong's avatar
wuyangyong 已提交
289

290
    if (ops->mount == RT_NULL) /* there is no mount implementation */
wuyangyong's avatar
wuyangyong 已提交
291
    {
292
		if (dev_id != RT_NULL) rt_device_close(dev_id);
293
    	dfs_lock();
wuyangyong's avatar
wuyangyong 已提交
294 295
        /* clear filesystem table entry */
        rt_memset(fs, 0, sizeof(struct dfs_filesystem));
296
		dfs_unlock();
wuyangyong's avatar
wuyangyong 已提交
297

298
		rt_free(fullpath);
wuyangyong's avatar
wuyangyong 已提交
299 300 301 302
        rt_set_errno(-DFS_STATUS_ENOSYS);
        return -1;
    }
    /* call mount of this filesystem */
303
    else if (ops->mount(fs, rwflag, data) < 0)
wuyangyong's avatar
wuyangyong 已提交
304 305
    {
        /* close device */
306
        if (dev_id != RT_NULL) rt_device_close(fs->dev_id);
wuyangyong's avatar
wuyangyong 已提交
307

308 309
        /* mount failed */
		dfs_lock();
wuyangyong's avatar
wuyangyong 已提交
310 311
        /* clear filesystem table entry */
        rt_memset(fs, 0, sizeof(struct dfs_filesystem));
312
		dfs_unlock();
313

314
		rt_free(fullpath);
315
		return -1;
wuyangyong's avatar
wuyangyong 已提交
316 317 318
    }

    return 0;
319 320

err1:
321
    dfs_unlock();
322 323
	if (fullpath != RT_NULL) rt_free(fullpath);

wuyangyong's avatar
wuyangyong 已提交
324
    return -1;
325 326
}

327 328 329 330 331 332 333
/**
 * this function will umount a file system on specified path.
 *
 * @param specialfile the specified path which mounted a file system.
 *
 * @return 0 on successful or -1 on failed.
 */
334 335
int dfs_unmount(const char *specialfile)
{
wuyangyong's avatar
wuyangyong 已提交
336 337 338
    char *fullpath;
    struct dfs_filesystem* fs = RT_NULL;

339 340
    fullpath = dfs_normalize_path(RT_NULL, specialfile);
    if (fullpath == RT_NULL)
wuyangyong's avatar
wuyangyong 已提交
341 342 343 344
    {
        rt_set_errno(-DFS_STATUS_ENOTDIR);
        return -1;
    }
345

346 347
    /* lock filesystem */
    dfs_lock();
348

wuyangyong's avatar
wuyangyong 已提交
349 350 351 352 353
    fs = dfs_filesystem_lookup(fullpath);
    if (fs != RT_NULL && fs->ops->unmount != RT_NULL && fs->ops->unmount(fs) < 0)
    {
        goto err1;
    }
354

wuyangyong's avatar
wuyangyong 已提交
355
    /* close device, but do not check the status of device */
B
bernard.xiong@gmail.com 已提交
356 357
	if (fs->dev_id != RT_NULL)
	    rt_device_close(fs->dev_id);
358

wuyangyong's avatar
wuyangyong 已提交
359 360
    /* clear this filesystem table entry */
    rt_memset(fs, 0, sizeof(struct dfs_filesystem));
361

362
	dfs_unlock();
363
	rt_free(fullpath);
364

wuyangyong's avatar
wuyangyong 已提交
365
    return 0;
366 367

err1:
368
	dfs_unlock();
369
	rt_free(fullpath);
370

wuyangyong's avatar
wuyangyong 已提交
371
    return -1;
372
}
373 374 375 376

/**
 * make a file system on the special device
 *
B
bernard.xiong@gmail.com 已提交
377 378
 * @param fs_name the file system name
 * @param device_name the special device name
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
 *
 * @return 0 on successful, otherwise failed.
 */
int dfs_mkfs(const char* fs_name, const char* device_name)
{
    int index;

	/* lock filesystem */
	dfs_lock();
    /* find the file system operations */
    for (index = 0; index < DFS_FILESYSTEM_TYPES_MAX; index++)
    {
        if (filesystem_operation_table[index] != RT_NULL &&
                strcmp(filesystem_operation_table[index]->name, fs_name) == 0)
        {
			/* find file system operation */
			const struct dfs_filesystem_operation* ops = filesystem_operation_table[index];
			dfs_unlock();

			if (ops->mkfs != RT_NULL)
				return ops->mkfs(device_name);

			break;
        }
    }
	dfs_unlock();

	return -1;
}

/**
 * this function will return the information about a mounted file system.
 *
 * @param path the path which mounted file system.
 * @param buffer the buffer to save the returned information.
 *
 * @return 0 on successful, others on failed.
 */
417
int dfs_statfs(const char* path, struct statfs* buffer)
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
{
	struct dfs_filesystem* fs;

	fs = dfs_filesystem_lookup(path);
	if (fs != NULL)
	{
		if (fs->ops->statfs!= RT_NULL)
			return fs->ops->statfs(fs, buffer);
	}

	return -1;
}

#ifdef RT_USING_FINSH
#include <finsh.h>
void mkfs(const char* fs_name, const char* device_name)
{
	dfs_mkfs(fs_name, device_name);
}
FINSH_FUNCTION_EXPORT(mkfs, make a file system);

void df(const char* path)
{
441
	struct statfs buffer;
442 443 444 445 446 447 448 449 450

	if (dfs_statfs(path, &buffer) == 0)
	{
		rt_kprintf("disk free: %d block[%d bytes per block]\n", buffer.f_bfree, buffer.f_bsize);
	}
}
FINSH_FUNCTION_EXPORT(df, get disk free);
#endif

B
bernard.xiong@gmail.com 已提交
451
/* @} */