static int fatfs_fcntl(mount_point_t *point, file_t *file, int cmd, int arg) { privinfo_t *priv = file->ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } switch (cmd) { case F_GETFL: return file->flags; case F_SETFL: if ((!(file->flags & FWRITE)) && (arg & FWRITE)) { seterrno(EINVAL); return -1; } file->flags = arg; return 0; default: seterrno(EINVAL); return -1; } }
/********************************************************************************************************* ** Function name: __vfs_close ** Descriptions: 关闭文件 ** input parameters: pid 任务 ID ** fd 文件描述符 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ int __vfs_close(pid_t pid, int fd) { int ret; vfs_file_begin(pid); if (point->fs->close == NULL) { vfs_file_end(pid); seterrno(ENOSYS); return -1; } seterrno(0); if (atomic_dec_and_test(&file->ref)) { ret = point->fs->close(point, file); if (ret == 0) { mutex_lock(&info_lock[pid], 0); info->files[fd] = NULL; mutex_unlock(&info_lock[pid]); vfs_file_free(file); atomic_dec(&point->ref); return ret; } else { atomic_inc(&file->ref); } } else { ret = 0; } vfs_file_end(pid); return ret; }
static int fatfs_mount(mount_point_t *point, device_t *dev, const char *dev_name, const char *param) { FATFS *fs; FRESULT res; if (dev == NULL) { seterrno(EINVAL); return -1; } fs = (FATFS *)kmalloc(sizeof(FATFS), GFP_KERNEL); if (fs != NULL) { memset(fs, 0, sizeof(FATFS)); res = f_mount(0, fs); if (res != FR_OK) { fatfs_result_to_errno(res); kfree(fs); return -1; } else { point->ctx = fs; fs->drv = dev; return 0; } } else { seterrno(ENOMEM); return -1; } }
/********************************************************************************************************* ** Function name: vfs_write ** Descriptions: 写文件 ** input parameters: fd 文件描述符 ** buf 数据缓冲区 ** len 新长度 ** output parameters: NONE ** Returned value: 成功写入的字节数 OR -1 *********************************************************************************************************/ ssize_t vfs_write(int fd, const void *buf, size_t len) { ssize_t slen; pid_t pid = getpid(); if (buf == NULL || len < 0) { seterrno(EINVAL); return -1; } if (len == 0) { seterrno(0); return 0; } { vfs_file_begin(pid); if (!(file->flags & FWRITE)) { vfs_file_end(pid); seterrno(EIO); return -1; } if (point->fs->write == NULL) { vfs_file_end(pid); seterrno(ENOSYS); return -1; } seterrno(0); slen = point->fs->write(point, file, buf, len); vfs_file_end(pid); return slen; } }
/** \brief Initialise a \e libcaca canvas. * * Initialise internal \e libcaca structures and the backend that will * be used for subsequent graphical operations. It must be the first * \e libcaca function to be called in a function. caca_free_canvas() * should be called at the end of the program to free all allocated resources. * * Both the cursor and the canvas' handle are initialised at the top-left * corner. * * If an error occurs, NULL is returned and \b errno is set accordingly: * - \c EINVAL Specified width or height is invalid. * - \c ENOMEM Not enough memory for the requested canvas size. * * \param width The desired canvas width * \param height The desired canvas height * \return A libcaca canvas handle upon success, NULL if an error occurred. */ caca_canvas_t * caca_create_canvas(int width, int height) { caca_canvas_t *cv; if(width < 0 || height < 0) { seterrno(EINVAL); return NULL; } cv = malloc(sizeof(caca_canvas_t)); if(!cv) goto nomem; cv->refcount = 0; cv->autoinc = 0; cv->resize_callback = NULL; cv->resize_data = NULL; cv->frame = 0; cv->framecount = 1; cv->frames = malloc(sizeof(struct caca_frame)); if(!cv->frames) { free(cv); goto nomem; } cv->frames[0].width = cv->frames[0].height = 0; cv->frames[0].chars = NULL; cv->frames[0].attrs = NULL; cv->frames[0].x = cv->frames[0].y = 0; cv->frames[0].handlex = cv->frames[0].handley = 0; cv->frames[0].curattr = 0; cv->frames[0].name = strdup("frame#00000000"); _caca_load_frame_info(cv); caca_set_color_ansi(cv, CACA_DEFAULT, CACA_TRANSPARENT); cv->ndirty = 0; cv->dirty_disabled = 0; cv->ff = NULL; if(caca_resize(cv, width, height) < 0) { int saved_errno = geterrno(); free(cv->frames[0].name); free(cv->frames); free(cv); seterrno(saved_errno); return NULL; } return cv; nomem: seterrno(ENOMEM); return NULL; }
/* * 写 xxx */ static ssize_t xxx_write(void *ctx, file_t *file, const void *buf, size_t len) { privinfo_t *priv = ctx; int ret; if (priv == NULL) { seterrno(EINVAL); return -1; } __again: if (atomic_read(&priv->select.flags) & VFS_FILE_ERROR) { seterrno(EIO); return -1; } if (0) { /* 如果没有空间可写 */ ret = vfs_block_helper(&priv->select, xxx_scan, ctx, file, VFS_FILE_WRITEABLE); if (ret <= 0) { return ret; } else { goto __again; } } { /* * 完成写操作 */ return 0; } }
/********************************************************************************************************* ** Function name: socket_priv_fd ** Descriptions: 获得 socket 的私有文件描述符 ** input parameters: fd IO 系统文件描述符 ** output parameters: ctx 上下文 ** Returned value: socket 的私有文件描述符 *********************************************************************************************************/ int socket_priv_fd(int fd, void **ctx) { file_t *file; device_t *dev; privinfo_t *priv; int sock_fd; file = vfs_get_file(fd); if (file != NULL) { if (file->type & VFS_FILE_TYPE_SOCK) { dev = file->ctx; if (dev != NULL) { priv = dev->ctx; if (priv != NULL) { sock_fd = priv->sock_fd; *ctx = file; seterrno(0); return sock_fd; } } } seterrno(EFTYPE); } return -1; }
/* * 扫描 socket */ static int socket_scan(void *ctx, file_t *file, int flags) { privinfo_t *priv = ctx; int ret; int readable; int writeable; int error; if (priv == NULL) { seterrno(EINVAL); return -1; } extern int socket_stat(int sock_fd, int *readable, int *writeable, int *error); ret = socket_stat(priv->sock_fd, &readable, &writeable, &error); if (ret < 0) { seterrno(EINVAL); return -1; } ret = 0; if (readable && flags & VFS_FILE_READABLE) { ret |= VFS_FILE_READABLE; } if (writeable && flags & VFS_FILE_WRITEABLE) { ret |= VFS_FILE_WRITEABLE; } if (error && flags & VFS_FILE_ERROR) { ret |= VFS_FILE_ERROR; } return ret; }
/********************************************************************************************************* ** Function name: vfs_ftruncate ** Descriptions: 修改文件长度 ** input parameters: fd 文件描述符 ** len 新长度 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ int vfs_ftruncate(int fd, off_t len) { int ret; pid_t pid = getpid(); if (len < 0) { seterrno(EINVAL); return -1; } vfs_file_begin(pid); if (!(file->flags & FWRITE)) { vfs_file_end(pid); seterrno(EIO); return -1; } if (point->fs->ftruncate == NULL) { vfs_file_end(pid); seterrno(ENOSYS); return -1; } seterrno(0); ret = point->fs->ftruncate(point, file, len); vfs_file_end(pid); return ret; }
/********************************************************************************************************* ** Function name: socket_attach ** Descriptions: 联结 socket ** input parameters: sock_fd socket 的私有文件描述符 ** output parameters: NONE ** Returned value: IO 系统文件描述符 *********************************************************************************************************/ int socket_attach(int sock_fd) { char path[PATH_MAX]; int fd; privinfo_t *priv; reg_t reg; file_t *file; int err; priv = kmalloc(sizeof(privinfo_t), GFP_KERNEL); if (priv != NULL) { priv->sock_fd = sock_fd; device_init(priv); sprintf(path, "/dev/socket%d", sock_fd); reg = interrupt_disable(); if (device_create(path, "socket", priv) < 0) { interrupt_resume(reg); kfree(priv); return -1; } fd = vfs_open(path, O_RDWR, 0666); if (fd < 0) { geterrno(err); vfs_unlink(path); seterrno(err); interrupt_resume(reg); kfree(priv); return -1; } file = vfs_get_file(fd); if (file == NULL) { geterrno(err); vfs_close(fd); vfs_unlink(path); seterrno(err); interrupt_resume(reg); kfree(priv); return -1; } file->type = VFS_FILE_TYPE_SOCK; vfs_put_file(file); lwip_socket_set_ctx(sock_fd, priv); interrupt_resume(reg); seterrno(0); return fd; } else { seterrno(ENOMEM); return -1; } }
/********************************************************************************************************* ** Function name: vfs_unmount ** Descriptions: 取消挂载文件系统 ** input parameters: path 目录 PATH ** param 参数 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ int vfs_unmount(const char *path, const char *param) { mount_point_t *point; char *pathbuf; char *filepath; int ret; pathbuf = kmalloc(PATH_BUF_LEN, GFP_KERNEL); if (pathbuf == NULL) { seterrno(ENOMEM); return -1; } mutex_lock(&mount_point_lock, 0); point = vfs_mount_point_lookup2(pathbuf, &filepath, path); /* 查找挂载点 */ if (point == NULL) { mutex_unlock(&mount_point_lock); kfree(pathbuf); return -1; } if (point->fs->unmount == NULL) { mutex_unlock(&mount_point_lock); kfree(pathbuf); seterrno(ENOSYS); return -1; } if (atomic_read(&point->ref) != 0) { mutex_unlock(&mount_point_lock); kfree(pathbuf); seterrno(EBUSY); return -1; } vfs_sync(path); seterrno(0); ret = point->fs->unmount(point, param); /* 取消挂载文件系统 */ if (ret == 0) { if (point->dev != NULL) { atomic_dec(&point->dev->ref); } atomic_dec(&point->fs->ref); mount_point_remove(point); } mutex_unlock(&mount_point_lock); kfree(pathbuf); return ret; }
static long fatfs_telldir(mount_point_t *point, file_t *file) { privinfo_t *priv = file->ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } seterrno(ENOSYS); return -1; }
static int fatfs_seekdir(mount_point_t *point, file_t *file, long loc) { privinfo_t *priv = file->ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } seterrno(ENOSYS); return -1; }
static int fatfs_ioctl(mount_point_t *point, file_t *file, int cmd, void *arg) { privinfo_t *priv = file->ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } seterrno(ENOSYS); return -1; }
/* * 写 socket */ static ssize_t socket_write(void *ctx, file_t *file, const void *buf, size_t len) { privinfo_t *priv = ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } if (atomic_read(&priv->select.flags) & VFS_FILE_ERROR) { seterrno(EIO); return -1; } return lwip_send(priv->sock_fd, buf, len, 0); }
/* * 控制 socket */ static int socket_ioctl(void *ctx, file_t *file, int cmd, void *arg) { privinfo_t *priv = ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } if (atomic_read(&priv->select.flags) & VFS_FILE_ERROR) { seterrno(EIO); return -1; } return lwip_ioctl(priv->sock_fd, cmd, ua_to_ka(arg)); }
/* * 控制 xxx */ static int xxx_ioctl(void *ctx, file_t *file, int cmd, void *arg) { privinfo_t *priv = ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } if (atomic_read(&priv->select.flags) & VFS_FILE_ERROR) { seterrno(EIO); return -1; } return 0; }
int fchmod(int fd, mode_t mode) { Dir d, *dir; dir = _dirfstat(fd); if(dir == nil) return seterrno(); _nulldir(&d); d.mode = (dir->mode & ~0777) | (mode & 0777); free(dir); if(_dirfwstat(fd, &d) < 0) return seterrno(); return 0; }
int chmod(const char *path, mode_t mode) { Dir d, *dir; dir = _dirstat(path); if(dir == nil) return seterrno(); _nulldir(&d); d.mode = (dir->mode & ~0777) | (mode & 0777); free(dir); if(_dirwstat(path, &d) < 0) return seterrno(); return 0; }
/********************************************************************************************************* ** Function name: vfs_lseek ** Descriptions: 调整文件读写位置 ** input parameters: fd 文件描述符 ** offset 偏移 ** whence 调整的位置 ** output parameters: NONE ** Returned value: 新的读写位置 OR -1 *********************************************************************************************************/ off_t vfs_lseek(int fd, off_t offset, int whence) { pid_t pid = getpid(); vfs_file_begin(pid); if (point->fs->lseek == NULL) { vfs_file_end(pid); seterrno(ENOSYS); return -1; } seterrno(0); offset = point->fs->lseek(point, file, offset, whence); vfs_file_end(pid); return offset; }
/********************************************************************************************************* ** Function name: vfs_mount_point_lookup ** Descriptions: 查找挂载点, PATH 不能是挂载点 ** input parameters: pathbuf 路径临时缓冲区 ** path 路径 ** output parameters: ppath 指向去掉挂载点后的路径 ** Returned value: 挂载点 OR NULL *********************************************************************************************************/ mount_point_t *vfs_mount_point_lookup(char pathbuf[PATH_BUF_LEN], char **ppath, const char *path) { mount_point_t *point; char *tmp; if (path == NULL || strlen(path) > PATH_MAX - 1) { /* PATH 合法性检查 */ seterrno(EINVAL); return NULL; } if (path[0] == '/') { /* 如果是绝对路径 */ if (path[1] == '\0') { /* 不能是根目录 */ seterrno(EINVAL); return NULL; } strlcpy(pathbuf, path, PATH_MAX); } else { /* 如果是相对路径 */ /* * cwd 要以 / 号开头和结尾 */ int tid = gettid(); snprintf(pathbuf, PATH_BUF_LEN, "%s%s", cwd[tid], path); /* 在前面加入当前工作目录 */ } if (vfs_path_normalization(pathbuf, FALSE) < 0) { /* 正常化 PATH */ return NULL; } tmp = strchr(pathbuf + 1, '/'); /* 查找挂载点名后的 / 号 */ if (tmp == NULL) { /* 没有到 */ seterrno(EINVAL); return NULL; } if (tmp[1] == '\0') { /* 不能是挂载点 */ seterrno(EINVAL); return NULL; } *tmp = '\0'; /* 暂时去掉 / 号 */ point = mount_point_lookup(pathbuf); /* 查找挂载点 */ *tmp = '/'; /* 恢复 / 号 */ *ppath = tmp; if (point == NULL) { seterrno(ENOENT); } return point; }
/* * 关闭 socket */ static int socket_close(void *ctx, file_t *file) { privinfo_t *priv = ctx; reg_t reg; if (priv == NULL) { seterrno(EINVAL); return -1; } reg = interrupt_disable(); atomic_dec(dev_ref(file)); device_remove(file->ctx); file->ctx = NULL; lwip_close(priv->sock_fd); kfree(priv); interrupt_resume(reg); return 0; }
/** \brief Remove an area from the dirty rectangle list. * * Mark a cell area in the canvas as not dirty. For more information about * the dirty rectangles, see caca_get_dirty_rect(). * * Values such that \b xmin > \b xmax or \b ymin > \b ymax indicate that * the dirty rectangle is empty. They will be silently ignored. * * If an error occurs, -1 is returned and \b errno is set accordingly: * - \c EINVAL Specified rectangle coordinates are out of bounds. * * \param cv A libcaca canvas. * \param x The leftmost edge of the clean rectangle. * \param y The topmost edge of the clean rectangle. * \param width The width of the clean rectangle. * \param height The height of the clean rectangle. * \return 0 in case of success, -1 if an error occurred. */ int caca_remove_dirty_rect(caca_canvas_t *cv, int x, int y, int width, int height) { /* Clip arguments to canvas size */ if(x < 0) { width += x; x = 0; } if(x + width > cv->width) width = cv->width - x; if(y < 0) { height += y; y = 0; } if(y + height > cv->height) height = cv->height - y; /* Ignore empty and out-of-canvas rectangles */ if(width <= 0 || height <= 0) { seterrno(EINVAL); return -1; } /* FIXME: implement this function. It's OK to have it do nothing, * since we take a conservative approach in dirty rectangle handling, * but we ought to help the rendering eventually. */ return 0; }
/********************************************************************************************************* ** Function name: vfs_unselect_file ** Descriptions: 将当前任务从文件的等待列表中移除 ** input parameters: fd 文件描述符 ** flags 标志 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ int vfs_unselect_file(int fd, int flags) { int ret; pid_t pid = getpid(); vfs_file_begin(pid); if (point->fs->unselect == NULL) { vfs_file_end(pid); seterrno(ENOSYS); return -1; } seterrno(0); ret = point->fs->unselect(point, file, flags); vfs_file_end(pid); return ret; }
/********************************************************************************************************* ** Function name: vfs_dup2 ** Descriptions: 复制文件描述符到指定的文件描述符 ** input parameters: fd 文件描述符 ** to 指定的文件描述符 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ int vfs_dup2(int fd, int to) { int ret; pid_t pid = getpid(); vfs_file_begin(pid); ret = vfs_close(to); if (ret < 0) { vfs_file_end(pid); return ret; } mutex_lock(&info_lock[pid], 0); info->files[to] = file; mutex_unlock(&info_lock[pid]); atomic_inc(&file->ref); atomic_inc(&point->ref); vfs_file_end(pid); seterrno(0); return 0; }
/********************************************************************************************************* ** Function name: vfs_ioctl ** Descriptions: 控制文件 ** input parameters: fd 文件描述符 ** cmd 命令 ** arg 参数 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ int vfs_ioctl(int fd, int cmd, void *arg) { int ret; pid_t pid = getpid(); vfs_file_begin(pid); if (point->fs->ioctl == NULL) { vfs_file_end(pid); seterrno(ENOSYS); return -1; } seterrno(0); ret = point->fs->ioctl(point, file, cmd, arg); vfs_file_end(pid); return ret; }
static struct dirent *fatfs_readdir(mount_point_t *point, file_t *file) { privinfo_t *priv = file->ctx; FRESULT res; if (priv != NULL) { FILINFO info; priv->entry.d_name[0] = '\0'; #if _USE_LFN info.lfname = priv->entry.d_name; info.lfsize = sizeof(priv->entry.d_name); #endif res = f_readdir(&priv->dir, &info); if (res == FR_OK && info.fname[0] != '\0') { #if _USE_LFN if (info.lfname[0] == '\0') { strlcpy(priv->entry.d_name, info.fname, sizeof(priv->entry.d_name)); } #else strlcpy(priv->entry.d_name, info.fname, sizeof(priv->entry.d_name)); #endif priv->entry.d_ino = 0; return &priv->entry; } else { fatfs_result_to_errno(res); return NULL; } } else { seterrno(EINVAL); return NULL; } }
/********************************************************************************************************* ** Function name: vfs_fstat ** Descriptions: 判断文件是不是终端 ** input parameters: fd 文件描述符 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ int vfs_isatty(int fd) { int ret; pid_t pid = getpid(); vfs_file_begin(pid); if (point->fs->isatty == NULL) { vfs_file_end(pid); seterrno(0); return 0; } seterrno(0); ret = point->fs->isatty(point, file); vfs_file_end(pid); return ret; }
static int fatfs_access(mount_point_t *point, const char *path, int amode) { struct stat buf; int ret; ret = fatfs_stat(point, path, &buf); if (ret == 0) { int access_ok = 1; if ((amode & R_OK) && !(buf.st_mode & S_IRUSR)) { access_ok = 0; } if ((amode & W_OK) && !(buf.st_mode & S_IWUSR)) { access_ok = 0; } if ((amode & X_OK) && !(buf.st_mode & S_IXUSR)) { access_ok = 0; } if (!access_ok) { seterrno(EACCES); return -1; } else { return 0; } } else { return ret; } }
/********************************************************************************************************* ** Function name: mtdblock_create ** Descriptions: 创建 MTD 块设备 ** input parameters: path MTD 块设备路径 ** mtd_no MTD 设备号 ** start 开始块号 ** end 结束块号 ** reserved 保留块数 ** readonly 是否只读 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ int mtdblock_create(const char *path, long mtd_no, long start, long end, long reserved, bool_t readonly) { privinfo_t *priv; if (path == NULL) { seterrno(EINVAL); return -1; } priv = kmalloc(sizeof(privinfo_t), GFP_KERNEL); if (priv != NULL) { device_init(priv); priv->reserved = reserved; priv->start = start; priv->end = end; priv->readonly = readonly; mutex_lock(&mtd_lock, 0); priv->mtd = get_mtd_device(NULL, mtd_no); mutex_unlock(&mtd_lock); if (priv->mtd == NULL) { kfree(priv); seterrno(EINVAL); return -1; } if (device_create(path, "mtdblock", priv) < 0) { mutex_lock(&mtd_lock, 0); put_mtd_device(priv->mtd); mutex_unlock(&mtd_lock); kfree(priv); return -1; } seterrno(0); return 0; } else { seterrno(ENOMEM); return -1; } }