dfs.c 9.0 KB
Newer Older
1 2 3
/*
 * File      : dfs.c
 * This file is part of Device File System in RT-Thread RTOS
4
 * COPYRIGHT (C) 2004-2012, RT-Thread Development Team
5
 *
Y
yiyue.fang 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 20 21 22 23 24 25 26 27 28 29
 *
 * Change Logs:
 * Date           Author       Notes
 * 2005-02-22     Bernard      The first version.
 */

#include <dfs.h>
#include <dfs_fs.h>
#include <dfs_file.h>

/* Global variables */
30
const struct dfs_filesystem_operation *filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX];
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX];

/* device filesystem lock */
static struct rt_mutex fslock;

#ifdef DFS_USING_WORKDIR
char working_directory[DFS_PATH_MAX] = {"/"};
#endif

#ifdef DFS_USING_STDIO
struct dfs_fd fd_table[3 + DFS_FD_MAX];
#else
struct dfs_fd fd_table[DFS_FD_MAX];
#endif

/**
 * @addtogroup DFS
 */
49

50 51 52 53 54
/*@{*/

/**
 * this function will initialize device file system.
 */
B
Bernard Xiong 已提交
55
int dfs_init(void)
56
{
57
    /* clear filesystem operations table */
58
    rt_memset((void *)filesystem_operation_table, 0, sizeof(filesystem_operation_table));
59 60 61 62
    /* clear filesystem table */
    rt_memset(filesystem_table, 0, sizeof(filesystem_table));
    /* clean fd table */
    rt_memset(fd_table, 0, sizeof(fd_table));
63

64 65
    /* create device filesystem lock */
    rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_FIFO);
66 67

#ifdef DFS_USING_WORKDIR
68 69 70
    /* set current working directory */
    rt_memset(working_directory, 0, sizeof(working_directory));
    working_directory[0] = '/';
71
#endif
B
Bernard Xiong 已提交
72
	return 0;
73
}
B
Bernard Xiong 已提交
74
INIT_COMPONENT_EXPORT(dfs_init);
75 76 77 78 79 80

/**
 * this function will lock device file system.
 *
 * @note please don't invoke it on ISR.
 */
81
void dfs_lock(void)
82
{
83
    rt_err_t result;
84

85 86 87 88 89
    result = rt_mutex_take(&fslock, RT_WAITING_FOREVER);
    if (result != RT_EOK)
    {
        RT_ASSERT(0);
    }
90 91 92 93 94 95 96
}

/**
 * this function will lock device file system.
 *
 * @note please don't invoke it on ISR.
 */
97
void dfs_unlock(void)
98
{
99
    rt_mutex_release(&fslock);
100 101 102 103 104 105 106 107 108 109
}

/**
 * @ingroup Fd
 * This function will allocate a file descriptor.
 *
 * @return -1 on failed or the allocated file descriptor.
 */
int fd_new(void)
{
110 111
    struct dfs_fd *d;
    int idx;
112

113 114
    /* lock filesystem */
    dfs_lock();
115

116
    /* find an empty fd entry */
117
#ifdef DFS_USING_STDIO
118
    for (idx = 3; idx < DFS_FD_MAX + 3 && fd_table[idx].ref_count > 0; idx++);
119
#else
120
    for (idx = 0; idx < DFS_FD_MAX && fd_table[idx].ref_count > 0; idx++);
121 122
#endif

123
    /* can't find an empty fd entry */
124
#ifdef DFS_USING_STDIO
125
    if (idx == DFS_FD_MAX + 3)
126
#else
127
    if (idx == DFS_FD_MAX)
128
#endif
129 130 131 132
    {
        idx = -1;
        goto __result;
    }
133

134 135
    d = &(fd_table[idx]);
    d->ref_count = 1;
136
    d->magic = DFS_FD_MAGIC;
137 138

__result:
139 140
    dfs_unlock();
    return idx;
141 142 143 144 145 146 147 148 149 150 151
}

/**
 * @ingroup Fd
 *
 * This function will return a file descriptor structure according to file
 * descriptor.
 *
 * @return NULL on on this file descriptor or the file descriptor structure
 * pointer.
 */
152
struct dfs_fd *fd_get(int fd)
153
{
154
    struct dfs_fd *d;
155 156

#ifdef DFS_USING_STDIO
157 158
    if (fd < 3 || fd >= DFS_FD_MAX + 3)
        return RT_NULL;
159
#else
160 161
    if (fd < 0 || fd >= DFS_FD_MAX)
        return RT_NULL;
162 163
#endif

164 165
    dfs_lock();
    d = &fd_table[fd];
166

167 168 169 170 171 172 173
    /* check dfs_fd valid or not */
    if (d->magic != DFS_FD_MAGIC)
    {
        dfs_unlock();
        return RT_NULL;
    }

174 175 176
    /* increase the reference count */
    d->ref_count ++;
    dfs_unlock();
177

178
    return d;
179 180 181 182 183 184 185
}

/**
 * @ingroup Fd
 *
 * This function will put the file descriptor.
 */
186
void fd_put(struct dfs_fd *fd)
187
{
188
    RT_ASSERT(fd != RT_NULL);
189

190 191
    dfs_lock();
    fd->ref_count --;
192

193 194 195 196 197 198
    /* clear this fd entry */
    if (fd->ref_count == 0)
    {
        rt_memset(fd, 0, sizeof(struct dfs_fd));
    }
    dfs_unlock();
199 200
};

201
/**
202 203 204
 * @ingroup Fd
 *
 * This function will return whether this file has been opend.
205
 *
206 207 208 209
 * @param pathname the file path name.
 *
 * @return 0 on file has been open successfully, -1 on open failed.
 */
210
int fd_is_open(const char *pathname)
211
{
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
    char *fullpath;
    unsigned int index;
    struct dfs_filesystem *fs;
    struct dfs_fd *fd;

    fullpath = dfs_normalize_path(RT_NULL, pathname);
    if (fullpath != RT_NULL)
    {
        char *mountpath;
        fs = dfs_filesystem_lookup(fullpath);
        if (fs == RT_NULL)
        {
            /* can't find mounted file system */
            rt_free(fullpath);

            return -1;
        }

        /* get file path name under mounted file system */
        if (fs->path[0] == '/' && fs->path[1] == '\0')
            mountpath = fullpath;
233
        else
234 235 236
            mountpath = fullpath + strlen(fs->path);

        dfs_lock();
237 238 239
#ifdef DFS_USING_STDIO
        for (index = 3; index < DFS_FD_MAX+3; index++)
#else
240
        for (index = 0; index < DFS_FD_MAX; index++)
241
#endif
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
        {
            fd = &(fd_table[index]);
            if (fd->fs == RT_NULL)
                continue;

            if (fd->fs == fs && strcmp(fd->path, mountpath) == 0)
            {
                /* found file in file descriptor table */
                rt_free(fullpath);
                dfs_unlock();

                return 0;
            }
        }
        dfs_unlock();

        rt_free(fullpath);
    }

    return -1;
262 263 264 265 266 267 268 269 270 271
}

/**
 * this function will return a sub-path name under directory.
 *
 * @param directory the parent directory.
 * @param filename the filename.
 *
 * @return the subdir pointer in filename
 */
272
const char *dfs_subdir(const char *directory, const char *filename)
273
{
274
    const char *dir;
275

276 277
    if (strlen(directory) == strlen(filename)) /* it's a same path */
        return RT_NULL;
278

279 280 281 282 283
    dir = filename + strlen(directory);
    if ((*dir != '/') && (dir != filename))
    {
        dir --;
    }
284

285
    return dir;
286 287
}

288
/**
289 290
 * this function will normalize a path according to specified parent directory
 * and file name.
291 292 293 294
 *
 * @param directory the parent path
 * @param filename the file name
 *
295
 * @return the built full file path (absolute path)
296
 */
297
char *dfs_normalize_path(const char *directory, const char *filename)
298
{
299 300
    char *fullpath;
    char *dst0, *dst, *src;
301

302 303
    /* check parameters */
    RT_ASSERT(filename != RT_NULL);
304 305

#ifdef DFS_USING_WORKDIR
306 307
    if (directory == RT_NULL) /* shall use working directory */
        directory = &working_directory[0];
308
#else
309 310 311
    if ((directory == RT_NULL) && (filename[0] != '/'))
    {
        rt_kprintf(NO_WORKING_DIR);
312

313 314
        return RT_NULL;
    }
315 316
#endif

317 318 319 320
    if (filename[0] != '/') /* it's a absolute path, use it directly */
    {
        fullpath = rt_malloc(strlen(directory) + strlen(filename) + 2);

G
geniusgogo 已提交
321 322 323
        if (fullpath == RT_NULL)
            return RT_NULL;

324
        /* join path and file name */
325
        rt_snprintf(fullpath, strlen(directory) + strlen(filename) + 2,
326 327 328 329 330
            "%s/%s", directory, filename);
    }
    else
    {
        fullpath = rt_strdup(filename); /* copy string */
331

G
geniusgogo 已提交
332 333
        if (fullpath == RT_NULL)
            return RT_NULL;
334 335 336 337
    }

    src = fullpath;
    dst = fullpath;
338

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
    dst0 = dst;
    while (1)
    {
        char c = *src;

        if (c == '.')
        {
            if (!src[1]) src ++; /* '.' and ends */
            else if (src[1] == '/')
            {
                /* './' case */
                src += 2;

                while ((*src == '/') && (*src != '\0'))
                    src ++;
                continue;
            }
            else if (src[1] == '.')
            {
                if (!src[2])
                {
                    /* '..' and ends case */
                    src += 2;
                    goto up_one;
                }
                else if (src[2] == '/')
                {
                    /* '../' case */
                    src += 3;

                    while ((*src == '/') && (*src != '\0'))
                        src ++;
                    goto up_one;
                }
            }
        }

        /* copy up the next '/' and erase all '/' */
        while ((c = *src++) != '\0' && c != '/')
            *dst ++ = c;

        if (c == '/')
        {
            *dst ++ = '/';
            while (c == '/')
                c = *src++;

            src --;
        }
        else if (!c)
            break;

        continue;
392 393

up_one:
394 395 396
        dst --;
        if (dst < dst0)
        {
397
            rt_free(fullpath);
398 399 400 401 402 403 404 405 406 407 408 409 410 411
            return RT_NULL;
        }
        while (dst0 < dst && dst[-1] != '/')
            dst --;
    }

    *dst = '\0';

    /* remove '/' in the end of path if exist */
    dst --;
    if ((dst != fullpath) && (*dst == '/'))
        *dst = '\0';

    return fullpath;
412 413 414
}
/*@}*/