URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [readdir.c] - Rev 1765
Compare with Previous | Blame | View Log
/* * linux/fs/readdir.c * * Copyright (C) 1995 Linus Torvalds */ #include <linux/types.h> #include <linux/errno.h> #include <linux/stat.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> #include <asm/segment.h> /* * Traditional linux readdir() handling.. * * "count=1" is a special case, meaning that the buffer is one * dirent-structure in size and that the code can't handle more * anyway. Thus the special "fillonedir()" function for that * case (the low-level handlers don't need to care about this). */ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) struct old_linux_dirent { unsigned long d_ino; unsigned long d_offset; unsigned short d_namlen; char d_name[1]; }; struct readdir_callback { struct old_linux_dirent * dirent; int count; }; static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) { struct readdir_callback * buf = (struct readdir_callback *) __buf; struct old_linux_dirent * dirent; if (buf->count) return -EINVAL; buf->count++; dirent = buf->dirent; put_user(ino, &dirent->d_ino); put_user(offset, &dirent->d_offset); put_user(namlen, &dirent->d_namlen); memcpy_tofs(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); return 0; } asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count) { int error; struct file * file; struct readdir_callback buf; if (fd >= NR_OPEN || !(file = current->files->fd[fd])) return -EBADF; if (!file->f_op || !file->f_op->readdir) return -ENOTDIR; error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent)); if (error) return error; buf.count = 0; buf.dirent = dirent; error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir); if (error < 0) return error; return buf.count; } /* * New, all-improved, singing, dancing, iBCS2-compliant getdents() * interface. */ struct linux_dirent { unsigned long d_ino; unsigned long d_off; unsigned short d_reclen; char d_name[1]; }; struct getdents_callback { struct linux_dirent * current_dir; struct linux_dirent * previous; int count; int error; }; static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) { struct linux_dirent * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); dirent = buf->current_dir; buf->previous = dirent; put_user(ino, &dirent->d_ino); put_user(reclen, &dirent->d_reclen); memcpy_tofs(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); ((char *) dirent) += reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; } asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count) { struct file * file; struct linux_dirent * lastdirent; struct getdents_callback buf; int error; if (fd >= NR_OPEN || !(file = current->files->fd[fd])) return -EBADF; if (!file->f_op || !file->f_op->readdir) return -ENOTDIR; error = verify_area(VERIFY_WRITE, dirent, count); if (error) return error; buf.current_dir = (struct linux_dirent *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; error = file->f_op->readdir(file->f_inode, file, &buf, filldir); if (error < 0) return error; lastdirent = buf.previous; if (!lastdirent) return buf.error; put_user(file->f_pos, &lastdirent->d_off); return count - buf.count; }