/* +------------------------------------------------------------------------------ | Project : Device Filesystem +------------------------------------------------------------------------------ | Copyright 2004, 2005 www.fayfayspace.org. | All rights reserved. |------------------------------------------------------------------------------ | File : dfs_raw.c, the raw APIs of Device FileSystem |------------------------------------------------------------------------------ | Chang Logs: | Date Author Notes | 2005-02-22 ffxz The first version. +------------------------------------------------------------------------------ */ #include #include #include extern struct dfs_fd fd_table[]; /* +------------------------------------------------------------------------------ | Function : fd_new +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int fd_new(void) { struct dfs_fd* d; int idx; /* lock filesystem */ dfs_lock(); /* find an empty fd entry */ #ifdef DFS_USING_STDIO for (idx = 3; idx < DFS_FD_MAX + 3 && fd_table[idx].ref_count > 0; idx++); #else for (idx = 0; idx < DFS_FD_MAX && fd_table[idx].ref_count > 0; idx++); #endif /* can't find an empty fd entry */ #ifdef DFS_USING_STDIO if (idx == DFS_FD_MAX + 3) #else if (idx == DFS_FD_MAX) #endif { idx = -1; goto __result; } d = &(fd_table[idx]); d->ref_count = 1; __result: dfs_unlock(); return idx; } /* +------------------------------------------------------------------------------ | Function : fd_get +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ struct dfs_fd* fd_get(int fd) { struct dfs_fd* d; #ifdef DFS_USING_STDIO if ( fd < 3 || fd > DFS_FD_MAX + 3) return RT_NULL; #else if ( fd < 0 || fd > DFS_FD_MAX ) return RT_NULL; #endif d = &fd_table[fd]; dfs_lock(); d->ref_count ++; dfs_unlock(); return d; } /* +------------------------------------------------------------------------------ | Function : fd_put +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ void fd_put(struct dfs_fd* fd) { dfs_lock(); fd->ref_count --; /* clear this fd entry */ if ( fd->ref_count == 0 ) { rt_memset(fd, 0, sizeof(struct dfs_fd)); } dfs_unlock(); }; /* +------------------------------------------------------------------------------ | Function : dfile_raw_open +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_open(struct dfs_fd* fd, const char *path, int flags) { struct dfs_filesystem* fs; char *fullpath; #ifdef DFS_USING_WORKDIR char full_path[DFS_PATH_MAX + 1]; #endif int fspathlen, result; /* parameter check */ if ( fd == RT_NULL ) return -DFS_STATUS_EINVAL; /* make sure we have an absolute path */ fullpath = (char*)path; if ( fullpath[0] != '/') { #ifdef DFS_USING_WORKDIR /* build full path */ fullpath = &full_path[0]; dfs_lock(); build_fullpath(working_directory, path, fullpath); dfs_unlock(); #else #ifdef RT_USING_FINSH rt_kprintf("bad filename"); #endif return -1; #endif } dfs_log(DFS_DEBUG_INFO, ("open file:%s", fullpath)); /* find filesystem */ fs = dfs_filesystem_lookup(fullpath); if ( fs == RT_NULL ) return -DFS_STATUS_ENOENT; dfs_log(DFS_DEBUG_INFO, ("open in filesystem:%s", fs->ops->name)); fd->fs = fs; /* initilize the fd item */ fd->type = FT_REGULAR; //fd->ref_count = 1; fd->flags = flags; fd->size = 0; fd->pos = 0; fspathlen = strlen(fs->path); rt_memset(fd->path, 0, DFS_PATH_MAX + 1); if (*(fullpath + fspathlen) != '/') strcpy(fd->path, "/"); strcat(fd->path, fullpath + fspathlen); /* specific file system open routine */ if (fs->ops->open == RT_NULL) { /* clear fd */ rt_memset(fd->path, 0, DFS_PATH_MAX + 1); fd->type = FT_REGULAR; fd->ref_count = 0; fd->fs = RT_NULL; fd->flags = 0; fd->size = 0; fd->pos = 0; fd->data = RT_NULL; return -DFS_STATUS_ENOSYS; } if ((result = fs->ops->open(fd)) < 0) { /* clear fd */ fd->fs = RT_NULL; fd->flags = 0; fd->data = RT_NULL; dfs_log(DFS_DEBUG_INFO, ("open failed")); return result; } fd->flags |= DFS_F_OPEN; if ( flags & DFS_O_DIRECTORY ) { fd->type = FT_DIRECTORY; fd->flags |= DFS_F_DIRECTORY; } dfs_log(DFS_DEBUG_INFO, ("open successful")); return 0; } /* +------------------------------------------------------------------------------ | Function : dfile_raw_close +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_close(struct dfs_fd* fd) { int result = 0; if (fd != RT_NULL && fd->fs->ops->close != RT_NULL) result = fd->fs->ops->close(fd); /* close fd error, return */ if ( result < 0 ) return result; fd->flags &= ~DFS_F_OPEN; return result; } /* +------------------------------------------------------------------------------ | Function : dfile_raw_ioctl +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_ioctl(struct dfs_fd* fd, int cmd, void *args) { struct dfs_filesystem* fs; if (fd == RT_NULL || fd->type != FT_REGULAR) return -DFS_STATUS_EINVAL; fs = fd->fs; #if 0 /* not support right now */ if (cmd == FILEGETSIZE) { if (args == RT_NULL) return -DFS_STATUS_EINVAL; *((rt_uint32_t *) args) = fd->size; return 0; } else if (cmd == FILEGETPOS) { if (args == RT_NULL) return -DFS_STATUS_EINVAL; *((rt_uint32_t *) args) = fd->pos; return 0; } #endif if (fs->ops->ioctl != RT_NULL) return fs->ops->ioctl(fd, cmd, args); return -DFS_STATUS_ENOSYS; } /* +------------------------------------------------------------------------------ | Function : dfile_raw_read +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_read(struct dfs_fd* fd, void *buf, rt_size_t len) { struct dfs_filesystem* fs; int result = 0; if (fd == RT_NULL) return -DFS_STATUS_EINVAL; fs = (struct dfs_filesystem*) fd->fs; if (fs->ops->read == RT_NULL) return -DFS_STATUS_ENOSYS; if ( (result = fs->ops->read(fd, buf, len)) < 0 ) fd->flags |= DFS_F_EOF; return result; } /* +------------------------------------------------------------------------------ | Function : dfile_raw_getdents +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_getdents(struct dfs_fd* fd, struct dfs_dirent* dirp, rt_size_t nbytes) { struct dfs_filesystem* fs; /* parameter check */ if (fd == RT_NULL || fd->type != FT_DIRECTORY) return -DFS_STATUS_EINVAL; fs = (struct dfs_filesystem*) fd->fs; if (fs->ops->getdents != RT_NULL) return fs->ops->getdents(fd, dirp, nbytes); return -DFS_STATUS_ENOSYS; } /* +------------------------------------------------------------------------------ | Function : dfile_raw_unlink +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_unlink(const char *path) { struct dfs_filesystem* fs; char *fullpath, *real_path, search_path[DFS_PATH_MAX + 1]; #ifdef DFS_USING_WORKDIR char full_path[DFS_PATH_MAX+1]; #endif struct dfs_fd* fd; int index, fspathlen; /* Make sure we have an absolute path */ fullpath = (char*)path; if ( fullpath[0] != '/') { #ifdef DFS_USING_WORKDIR /* build full path */ fullpath = full_path; dfs_lock(); build_fullpath(working_directory, path, fullpath); dfs_unlock(); #else #ifdef RT_USING_FINSH rt_kprintf("bad filename"); #endif return -1; #endif } if ( (fs = dfs_filesystem_lookup(fullpath)) == RT_NULL) return -DFS_STATUS_ENOENT; /* Check whether file is already open */ dfs_lock(); for (index = 0; index < DFS_FD_MAX; index++) { fd = &(fd_table[index]); if (fd->fs == RT_NULL) continue; build_fullpath(fd->fs->path, fd->path, search_path); if (strcmp(fullpath, search_path) == 0) { dfs_unlock(); return -DFS_STATUS_EEXIST; } } dfs_unlock(); fspathlen = strlen(fs->path); real_path = search_path; rt_memset( real_path, 0, sizeof( real_path ) ); if (*(fullpath + fspathlen) != '/') strcpy(real_path, "/"); strcat(real_path, fullpath + fspathlen); if (fs->ops->unlink != RT_NULL) return fs->ops->unlink(fs, real_path); return -DFS_STATUS_ENOSYS; } /* +------------------------------------------------------------------------------ | Function : dfile_raw_write +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_write(struct dfs_fd* fd, const void *buf, rt_size_t len) { struct dfs_filesystem* fs = fd->fs; if (fd == RT_NULL) return -DFS_STATUS_EINVAL; if (fs->ops->write == RT_NULL) return -DFS_STATUS_ENOSYS; return fs->ops->write(fd, buf, len); } /* +------------------------------------------------------------------------------ | Function : dfile_raw_lseek +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_lseek(struct dfs_fd* fd, rt_off_t offset) { struct dfs_filesystem* fs = fd->fs; if (fd == RT_NULL) return -DFS_STATUS_EINVAL; if (fs->ops->lseek == RT_NULL) return -DFS_STATUS_ENOSYS; return fs->ops->lseek(fd, offset); } /* +------------------------------------------------------------------------------ | Function : dfile_raw_stat +------------------------------------------------------------------------------ | Description : get the file or directory stat description | | Parameters : path, the file or directory path | buf, the stat description will be saved in it | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_stat(const char *path, struct dfs_stat *buf) { struct dfs_filesystem* fs; char* fullpath, real_path[DFS_PATH_MAX + 1]; #ifdef DFS_USING_WORKDIR char full_path[DFS_PATH_MAX + 1]; #endif int fspathlen; fullpath = (char*)path; if ( fullpath[0] != '/' ) { #ifdef DFS_USING_WORKDIR /* build full path */ fullpath = full_path; dfs_lock(); build_fullpath(working_directory, path, fullpath); dfs_unlock(); #else #ifdef RT_USING_FINSH rt_kprintf("not support working directory, bad filename\n"); #endif return -1; #endif } if ( (fs = dfs_filesystem_lookup(fullpath)) == RT_NULL ) { dfs_log(DFS_DEBUG_ERROR, ("can't find mounted filesystem on this path:%s", fullpath)); return -DFS_STATUS_ENOENT; } fspathlen = strlen(fs->path); rt_memset(real_path, 0, sizeof(real_path)); if (*(fullpath + fspathlen) != '/') strcpy(real_path, "/"); strcat(real_path, fullpath + fspathlen); if (fs->ops->stat == RT_NULL) { dfs_log(DFS_DEBUG_ERROR, ("the filesystem didn't implement this function")); return -DFS_STATUS_ENOSYS; } return fs->ops->stat(fs, real_path, buf); } /* +------------------------------------------------------------------------------ | Function : dfile_raw_rename +------------------------------------------------------------------------------ | Description : | | Parameters : | Returns : | +------------------------------------------------------------------------------ */ int dfile_raw_rename(const char* oldpath, const char* newpath) { struct dfs_filesystem *oldfs, *newfs; char *oldfullpath, *newfullpath; #ifdef DFS_USING_WORKDIR /* Change DFS_PATH_MAX to DFS_PATH_MAX + 1, yi.qiu@2008.09.23*/ char old_realpath[DFS_PATH_MAX + 1], new_realpath[DFS_PATH_MAX + 1]; #endif oldfullpath = (char*)oldpath; newfullpath = (char*)newpath; if ( oldfullpath[0] != '/' ) { #ifdef DFS_USING_WORKDIR /* build full path */ oldfullpath = old_realpath; dfs_lock(); build_fullpath(working_directory, oldpath, oldfullpath); dfs_unlock(); #else rt_kprintf("bad filename\n"); return -1; #endif } if ( newfullpath[0] != '/' ) { #ifdef DFS_USING_WORKDIR /* build full path */ newfullpath = new_realpath; dfs_lock(); build_fullpath(working_directory, newpath, newfullpath); dfs_unlock(); #else rt_kprintf("bad filename"); return -1; #endif } if ( (oldfs = dfs_filesystem_lookup(oldfullpath)) == RT_NULL ) { return -DFS_STATUS_ENOENT; } if ( (newfs = dfs_filesystem_lookup(newfullpath)) == RT_NULL ) { return -DFS_STATUS_ENOENT; } if ( oldfs == newfs ) { if ( oldfs->ops->rename == RT_NULL ) return -DFS_STATUS_ENOSYS; return oldfs->ops->rename(oldfs, oldfullpath, newfullpath); } /* not at same file system, return EXDEV */ return -DFS_STATUS_EXDEV; } #ifdef RT_USING_FINSH #include static char fullpath[256 + 1]; static struct dfs_fd fd; static struct dfs_dirent dirent; void __ls(const char* pathname) { struct dfs_stat stat; int length; /* list directory */ if ( dfile_raw_open(&fd, pathname, DFS_O_DIRECTORY) == 0 ) { rt_kprintf("Directory %s:\n", pathname); do { rt_memset(&dirent, 0, sizeof(struct dfs_dirent)); length = dfile_raw_getdents(&fd, &dirent, sizeof(struct dfs_dirent)); if ( length > 0 ) { rt_memset(&stat, 0, sizeof(struct dfs_stat)); /* build full path for each file */ strncpy(fullpath, pathname, 256); strcat(fullpath, "/"); strcat(fullpath, dirent.d_name); dfile_raw_stat(fullpath, &stat); if ( stat.st_mode & DFS_S_IFDIR ) { rt_kprintf("%s\t\t\n", dirent.d_name); } else { rt_kprintf("%s\t\t%lu\n", dirent.d_name, stat.st_size); } } }while(length > 0); dfile_raw_close(&fd); } else { rt_kprintf("No such directory\n"); } } FINSH_FUNCTION_EXPORT(__ls, list directory contents) void __mkdir(const char* pathname) { /* make a new directory */ if (dfile_raw_open(&fd, pathname, DFS_O_DIRECTORY | DFS_O_CREAT) == 0) { dfile_raw_close(&fd); } else rt_kprintf("Can't mkdir %s\n", pathname); } FINSH_FUNCTION_EXPORT(__mkdir, make a directory) void __rm(const char* filename) { if (dfile_raw_unlink(filename) < 0) { rt_kprintf("Delete %s failed\n", filename); } } FINSH_FUNCTION_EXPORT(__rm, remove files or directories) void __cat(const char* filename) { rt_uint32_t length; char buffer[81]; if (dfile_raw_open(&fd, filename, DFS_O_RDONLY) < 0) { rt_kprintf("Open %s failed\n", filename); return; } do { rt_memset(buffer, 0, sizeof(buffer)); length = dfile_raw_read(&fd, buffer, 81); if (length > 0) { rt_kprintf("%s", buffer); } }while (length > 0); dfile_raw_close(&fd); } FINSH_FUNCTION_EXPORT(__cat, print file) #ifndef FINSH_USING_SYMTAB void dfs_export_finsh(void) { finsh_syscall_append("ls", (syscall_func)__ls); finsh_syscall_append("mkdir", (syscall_func)__mkdir); finsh_syscall_append("rm", (syscall_func)__rm); finsh_syscall_append("cat", (syscall_func)__cat); } #endif #endif