//XXX:carefull, the dentry type is not supported by all fs static void dir_parse(i parent_fd) { ++depth; u8 dirents[DIRENTS_BUF_SZ]; while(1){ l r=getdents64(parent_fd,dirents,DIRENTS_BUF_SZ); if(ISERR(r)){ PERR("ERROR(%ld):getdents error\n",r); exit(-1); } if(!r) break; l j=0; while(j<r){ struct dirent64 *d=(struct dirent64*)(dirents+j); dout(d); if(d->type==DT_DIR&&!is_current(d->name)&&!is_parent(d->name)){ i dir_fd; do dir_fd=(i)openat(parent_fd,d->name,RDONLY|NONBLOCK); while(dir_fd==-EINTR); if(ISERR(dir_fd)) PERR("ERROR(%d):unable to open subdir:%s\n",dir_fd,d->name); else{ dir_parse(dir_fd); l r1; do r1=close(dir_fd); while(r1==-EINTR); } } j+=d->rec_len; } } depth--; }
struct dirent64* readdir64(DIR *d) { if (!d->num || (d->cur += ((struct dirent64*)(d->buf+d->cur))->d_reclen)>=d->num) { int res=getdents64(d->fd,(struct dirent64*)d->buf, sizeof (d->buf)-1); if (res<=0) return 0; d->num=res; d->cur=0; } return (struct dirent64*)(d->buf+d->cur); }
int main(int ac, char **av) { int lc; char *msg; int rval, fd; struct linux_dirent64 dir64; struct linux_dirent dir; if ((msg = parse_opts(ac, av, options, &help)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; if ((fd = open("test", O_CREAT | O_RDWR, 0777)) == -1) tst_brkm(TBROK | TERRNO, cleanup, "open of file failed"); if (longsyscall) rval = getdents64(fd, &dir64, sizeof(dir64)); else rval = getdents(fd, &dir, sizeof(dir)); /* * Calling with a non directory file descriptor should give * an ENOTDIR error. */ if (rval < 0) { TEST_ERROR_LOG(errno); switch (errno) { case ENOTDIR: tst_resm(TPASS, "getdents failed as expected with ENOTDIR"); break; case ENOSYS: tst_resm(TCONF, "syscall not implemented"); break; break; default: tst_resm(TFAIL | TERRNO, "getdents failed unexpectedly"); break; } } else { tst_resm(TFAIL, "getdents call succeeded unexpectedly"); } if (close(fd) == -1) tst_brkm(TBROK, cleanup, "fd close failed"); } cleanup(); tst_exit(); }
struct dirent64* readdir64(DIR *d) { struct linux_dirent64 *ld = d->num ? (struct linux_dirent64*)(d->buf+d->cur) : NULL; if (!d->num || (d->cur += ld->d_reclen)>=d->num) { int res=getdents64(d->fd,(struct linux_dirent64*)d->buf, __DIRSTREAM_BUF_SIZE-1); if (res<=0) return 0; d->num=res; d->cur=0; d->is_64=1; } /* \todo: ensure that dirent64 and linux_dirent64 are compatible */ return (struct dirent64*)(d->buf+d->cur); }
struct dirent64 *readdir64(DIR *dir){ register struct dirent64 *this; this=((struct dirent64 *) (dir->buf + dir->bufpos)); if (dir->bufsize == 0 || (dir->bufpos += this->d_reclen) >= dir->bufsize) { dir->bufsize = getdents64(dir->fd,(struct dirent64 *)dir->buf,PURE_DIRBUF_SIZE-1); if (dir->bufsize <= 0) return NULL; else dir->bufpos=0; } this=((struct dirent64 *) (dir->buf + dir->bufpos)); return this; }
static void test_ebadf(void) { int fd = -5; struct linux_dirent64 dirp64; struct linux_dirent dirp; if (longsyscall) getdents64(fd, &dirp64, sizeof(dirp64)); else getdents(fd, &dirp, sizeof(dirp)); print_test_result(errno, EBADF); }
/* * Support function: * Close all open file descriptors greater than or equal to lowfd. * This is executed in the child of vfork(), so we must not call * opendir() / readdir() because that would alter the parent's * address space. We use the low-level getdents64() system call. * Return non-zero on error. */ static int spawn_closefrom(int lowfd, void *buf) { int procfd; int fd; int buflen; dirent64_t *dp; dirent64_t *dpend; if (lowfd < 0) lowfd = 0; /* * Close lowfd right away as a hedge against failing * to open the /proc file descriptor directory due * all file descriptors being currently used up. */ (void) __close(lowfd++); if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) { /* * We could not open the /proc file descriptor directory. * Just fail and be done with it. */ return (-1); } for (;;) { /* * Collect a bunch of open file descriptors and close them. * Repeat until the directory is exhausted. */ dp = (dirent64_t *)buf; if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) { (void) __close(procfd); break; } dpend = (dirent64_t *)((uintptr_t)buf + buflen); do { /* skip '.', '..' and procfd */ if (dp->d_name[0] != '.' && (fd = atoi(dp->d_name)) != procfd && fd >= lowfd) (void) __close(fd); dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen); } while (dp < dpend); } return (0); }
static void test_enotdir(void) { int fd; struct linux_dirent64 dir64; struct linux_dirent dir; fd = SAFE_OPEN(cleanup, "test", O_CREAT | O_RDWR); if (longsyscall) getdents64(fd, &dir64, sizeof(dir64)); else getdents(fd, &dir, sizeof(dir)); print_test_result(errno, ENOTDIR); SAFE_CLOSE(cleanup, fd); }
static void test_einval(void) { int fd; char buf[1]; fd = SAFE_OPEN(cleanup, ".", O_RDONLY); /* Pass one byte long buffer. The result should be EINVAL */ if (longsyscall) getdents64(fd, (void *)buf, sizeof(buf)); else getdents(fd, (void *)buf, sizeof(buf)); print_test_result(errno, EINVAL); SAFE_CLOSE(cleanup, fd); }
struct dirent64* readdir64(DIR *d) { #ifdef __NR_getdents64 static int trygetdents64=1; #endif static struct dirent64 d64; #ifdef __NR_getdents64 again: if (!trygetdents64) { #endif struct linux_dirent *ld = d->num ? (struct linux_dirent*)(d->buf+d->cur) : NULL; if (!d->num || (d->cur += ld->d_reclen)>=d->num) { int res=getdents(d->fd,(struct linux_dirent*)d->buf, __DIRSTREAM_BUF_SIZE-1); if (res<=0) return 0; d->num=res; d->cur=0;d->is_64=0; ld=(struct linux_dirent*)(d->buf+d->cur); } d64.d_ino=ld->d_ino; d64.d_off=ld->d_off; d64.d_reclen=ld->d_reclen; strcpy(d64.d_name,ld->d_name); d64.d_type=0; /* is this correct? */ return &d64; #ifdef __NR_getdents64 } { struct linux_dirent64 *ld = d->num ? (struct linux_dirent64*)(d->buf+d->cur) : NULL; if (!d->num || (d->cur += ld->d_reclen)>=d->num) { int res=getdents64(d->fd,(struct linux_dirent64*)d->buf,__DIRSTREAM_BUF_SIZE); if (res<=0) { if (errno==ENOSYS) { trygetdents64=0; goto again; } return 0; } d->num=res; d->cur=0; d->is_64=1; } } /* \todo: ensure that dirent64 and linux_dirent64 are compatible */ return (struct dirent64*)(d->buf+d->cur); #endif }
struct dirent64* readdir64(DIR *d) { #ifdef __NR_getdents64 static int trygetdents64=1; #endif struct dirent* o; static struct dirent64 d64; #ifdef __NR_getdents64 again: if (!trygetdents64) { #endif if (!d->num || (d->cur += ((struct dirent*)(d->buf+d->cur))->d_reclen)>=d->num) { int res=getdents(d->fd,(struct dirent*)d->buf, sizeof (d->buf)-1); if (res<=0) return 0; d->num=res; d->cur=0; } o=(struct dirent*)(d->buf+d->cur); d64.d_ino=o->d_ino; d64.d_off=o->d_off; d64.d_reclen=o->d_reclen; strcpy(d64.d_name,o->d_name); d64.d_type=0; /* is this correct? */ return &d64; #ifdef __NR_getdents64 } if (!d->num || (d->cur += ((struct dirent64*)(d->buf+d->cur))->d_reclen)>=d->num) { int res=getdents64(d->fd,(struct dirent64*)d->buf,sizeof (d->buf)); if (res<=0) { if (errno==ENOSYS) { trygetdents64=0; goto again; } return 0; } d->num=res; d->cur=0; } return (struct dirent64*)(d->buf+d->cur); #endif }
static void test_enoent(void) { int fd; struct linux_dirent64 dir64; struct linux_dirent dir; SAFE_MKDIR(cleanup, TEST_DIR, DIR_MODE); fd = SAFE_OPEN(cleanup, TEST_DIR, O_DIRECTORY); if (rmdir(TEST_DIR) == -1) { tst_brkm(TBROK | TERRNO, cleanup, "rmdir(%s) failed", TEST_DIR); } if (longsyscall) getdents64(fd, &dir64, sizeof(dir64)); else getdents(fd, &dir, sizeof(dir)); print_test_result(errno, ENOENT); SAFE_CLOSE(cleanup, fd); }
static struct direct64 * internal_readdir(DIR *dirp) { struct dirent64 *dp; /* -> directory data */ int saveloc = 0; if (dirp->dd_size != 0) { dp = (struct dirent64 *)&dirp->dd_buf[dirp->dd_loc]; saveloc = dirp->dd_loc; /* save for possible EOF */ dirp->dd_loc += dp->d_reclen; } if (dirp->dd_loc >= dirp->dd_size) dirp->dd_loc = dirp->dd_size = 0; if (dirp->dd_size == 0 && /* refill buffer */ (dirp->dd_size = getdents64(dirp->dd_fd, (struct dirent64 *)dirp->dd_buf, DIRBUF)) <= 0) { if (dirp->dd_size == 0) /* This means EOF */ dirp->dd_loc = saveloc; /* EOF so save for telldir */ return (NULL); /* error or EOF */ } dp = (struct dirent64 *)&dirp->dd_buf[dirp->dd_loc]; /* Copy dirent into direct */ dc64.d_ino = dp->d_ino; dc64.d_reclen = dp->d_reclen; dc64.d_namlen = (ushort_t)strlen(dp->d_name); if (dc64.d_namlen > MAXNAMLEN) { errno = ENAMETOOLONG; return (NULL); } (void) strcpy(dc64.d_name, dp->d_name); return (&dc64); }
static int ftfs_recursive_delete(char * pathname) { int fd, num, cnt; void * buf; struct dirent64 * dirp; char *full_name = kzalloc(PATH_MAX, GFP_KERNEL); if (!full_name) return -ENOMEM; ftfs_log(__func__, "pathname = %s",pathname); fd = open(pathname, O_RDONLY, 0); if (fd < 0) { ftfs_log(__func__, "open failed for recursive deletion %d",fd); kfree(full_name); return fd; } buf = kzalloc(BUF_SIZE, GFP_KERNEL); if (!buf) { kfree(full_name); close(fd); return -ENOMEM; } dirp = buf; while (1) { num = getdents64(fd, (struct linux_dirent64 *)dirp, BUF_SIZE); if (num < 0) { kfree(buf); kfree(full_name); close(fd); ftfs_log(__func__, "getdents64 failed for recursive deletion %d",ftfs_get_errno()); return 0-ftfs_get_errno(); //this looks weird but to keep consistent with getdents64 interface... } if (num == 0) { goto out; } cnt = num; while (cnt > 0) { struct stat st; int ret; char *name = dirp->d_name; if (strcmp(name,".") == 0) goto dot; if (strcmp(name, "..") == 0) goto dot; strcpy(full_name, pathname); strcat(full_name, "/"); strcat(full_name, dirp->d_name); ret = ftfs_sys_newlstat(full_name, &st); WARN_ON_ONCE(ret); if (ret < 0) { ftfs_log(__func__, "newlstat failed for recursive deletion %d",ret); kfree(buf); kfree(full_name); close(fd); return ret; } if(S_ISDIR(st.st_mode)) { ftfs_recursive_delete(full_name); } else { #ifdef __TOKU_MISC_DEBUG ftfs_log(__func__, "going to delete file%s", full_name); #endif unlink(full_name); } dot: cnt -= dirp->d_reclen; dirp = (void *) dirp + dirp->d_reclen; } dirp = buf; memset(dirp,0, BUF_SIZE); } out: close(fd); kfree(buf); kfree(full_name); #ifdef __TOKU_MISC_DEBUG ftfs_log(__func__, "going to delete dir:%s", pathname); #endif rmdir(pathname); return 0; }