On Tue, Dec 04, 2007 at 07:34:37PM +0200, Timo Sirainen wrote:
On Tue, 2007-12-04 at 12:12 -0500, Dean Brooks wrote:
However, no matter what configuration changes I make, Dovecot refuses to list a filesystem mailbox unless you specify a wildcard:
x list "" Sent x OK List completed.
x list "" Sent*
- LIST (\NoInferiors \UnMarked) "/" "Sent" x OK List completed.
Were there any changes to the filesystem listing code? We're on NFS filesystem if it makes any difference.
That might explain it, but I can't think of any change that could have broken this.
Found it.
It affects anyone under Solaris 8 , and probably all other versions of Solaris.
In src/list/mailbox-list-fs-iter.c, in the function fs_list_dir_next(), the following code near the end of the function is the culprit:
if (i_strocpy(dir->dirent.d_name, fname,
sizeof(dir->dirent.d_name)) < 0) {
/* name too large.. shouldn't happen. */
continue;
}
To fix it, I changed it to:
if (i_strocpy(dir->dirent.d_name, fname, MAXNAMLEN) < 0) {
/* name too large.. shouldn't happen. */
continue;
}
It appears that sizeof(dir->dirent.d_name) always returns "1" under Solaris. Indeed, when I do a "man dirent", I see this:
The dirent structure is defined:
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[1];
};
The field d_name
is the beginning of the character array giving the name of
the directory entry. This name is null terminated and may
have at most MAXNAMLEN characters. This results in file
system independent directory entries being variable length
entities.
Turns out this is a common dirent portability issue that affects a few operating systems, including Solaris. I googled around and found other authors who have done crazy stuff like this:
#ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME strcpy(dirent->d_name, filename, MAXPATHLEN); #else strcpy(dirent->d_name, filename, sizeof(dirent->d_name)); #endif
There is probably a cleaner way to deal with this though. Anyway, it something that needs to be dealt with. From what I can tell, this is the only place in Dovecot where a sizeof() is done on d_name.
-- Dean Brooks dean@iglou.com