readdir 和 getdents 接口——读取的字节数?

readdir and getdents interfaces -- number of bytes read?

我正在开发 Cygwin,它没有实现 getdents, nor getdirentries

我正在处理的代码依赖于知道读取的字节数,即这些调用的 return。我似乎只有 readdir.

Cygwin 中缺少手册页。关于如何使这些接口兼容或如何获取从 readdir 读取的字节数的任何想法或现有文档?

Cygwin 的 struct dirent,如果相关:

struct dirent
{
  uint32_t __d_version;                 /* Used internally */
  ino_t d_ino;
  unsigned char d_type;
  unsigned char __d_unused1[3];
  __uint32_t __d_internal1;
  char d_name[NAME_MAX + 1];
};

编辑

使用getdentscode在函数readdir中(完整文件见link):

static int
mygetdents(int fd, struct dirent *buf, int n) {
  return syscall (getdents, fd, (void*) buf, n);
}

long
dirread(int fd, Dir **dp)
{
    char *buf;
    struct stat st;
    int n;

    *dp = 0;

    if(fstat(fd, &st) < 0)
        return -1;

    if(st.st_blksize < 8192)
        st.st_blksize = 8192;

    buf = malloc(st.st_blksize);
    if(buf == nil)
        return -1;

    n = mygetdents(fd, (void*)buf, st.st_blksize);
    if(n < 0){
        free(buf);
        return -1;
    }
    n = dirpackage(fd, buf, n, dp);
    free(buf);
    return n;
}

static int
dirpackage(int fd, char *buf, int n, Dir **dp)
{
    int oldwd;
    char *p, *str, *estr;
    int i, nstr, m;
    struct dirent *de;
    struct stat st, lst;
    Dir *d;

    n = countde(buf, n);
    if(n <= 0)
        return n;

    if((oldwd = open(".", O_RDONLY)) < 0)
        return -1;
    if(fchdir(fd) < 0)
        return -1;

    p = buf;
    nstr = 0;

    for(i=0; i<n; i++){
        de = (struct dirent*)p;
        memset(&lst, 0, sizeof lst);
        if(de->d_name[0] == 0)
            /* nothing */ {}
        else if(lstat(de->d_name, &lst) < 0)
            de->d_name[0] = 0;
        else{
            st = lst;
            if(S_ISLNK(lst.st_mode))
                stat(de->d_name, &st);
            nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
        }
        p += de->d_reclen;
    }

    d = malloc(sizeof(Dir)*n+nstr);
    if(d == nil){
        fchdir(oldwd);
        close(oldwd);
        return -1;
    }
    str = (char*)&d[n];
    estr = str+nstr;

    p = buf;
    m = 0;
    for(i=0; i<n; i++){
        de = (struct dirent*)p;
        if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){
            st = lst;
            if((lst.st_mode&S_IFMT) == S_IFLNK)
                stat(de->d_name, &st);
            _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
        }
        p += de->d_reclen;
    }

    fchdir(oldwd);
    close(oldwd);
    *dp = d;
    return m;
}

static int
countde(char *p, int n)
{
    char *e;
    int m;
    struct dirent *de;

    e = p+n;
    m = 0;
    while(p < e){
        de = (struct dirent*)p;
        if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
            break;
        if(de->d_name[0]=='.' && de->d_name[1]==0)
            de->d_name[0] = 0;
        else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
            de->d_name[0] = 0;
        m++;
        p += de->d_reclen;
    }
    return m;
}

我还没有弄明白 dirpackage,但我 认为 如果我能得到 return getdents 另一种方式。

从您发布到dirpackage方法的link:

for(i=0; i<n; i++){
    de = (struct dirent*)p;
    memset(&lst, 0, sizeof lst);
    if(de->d_name[0] == 0)
        /* nothing */ {}
    else if(lstat(de->d_name, &lst) < 0)
        de->d_name[0] = 0;
    else{
        st = lst;
        if(S_ISLNK(lst.st_mode))
            stat(de->d_name, &st);
        nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
    }
    p += de->d_reclen;
}

此处n来自:

n = countde(buf, n);

... n 的原始值由 getdents 系统调用的 return 提供。 countde 这个名字可能代表 "count directory entries".

从循环中可以看出,countde 中的 return 表示 getdents 调用编辑的 return 条目数。循环中的每次迭代都会处理一个目录条目 (de = (struct dirent*)p;),然后找到下一个 (p += de->d_reclen;)。

转换为使用 readdir 应该非常简单,因为它只 return 一个条目。