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

我正在处理的代码取决于知道读取的字节数,这是这些调用的返回。我似乎只有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中(有关完整文件,请参见链接):

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的含义,但是我想,如果我能以其他方式得到getdents的回报,我可能会解决这个问题。

最佳答案

从发布到dirpackage方法的链接中:

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 syscall的返回中提供的。名称countde可能代表“计数目录条目”。

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

转换为使用readdir应该很简单,因为它只会返回一个条目。

08-16 13:46