Extended filesystem attributes support

François Revol <[email protected]> Thu, 3 Jun 2004 11:10:56 -0400
Newsgroups gmane.emacs.xemacs.design
Message-ID <[email protected]>
Hello,
BeOS has been using extended filesystem attributes for years, 
and Linux has recently got some (weaker IMO) API to manipulate 
attributes on filesystems that support it.

In BeOS for example, they are used to store the file's mimetype, 
preferred application, folder's layouts for the file manager, 
ID3s (which are then easily searchable by queries, which Linux 
is far from able to do), mail data (from, to, subject, ...), and 
even the whole datas for People files, which are 0-length files 
with various attributes for contact informations, which a recent 
IM_Kit (multi-protocol instant messenger) extended to contain 
nicknames and networks. The default webbrowser (NetPositive) uses 
0-length files as bookmark items as well, and BeIDE, the default 
code editor, stores various things on files this way, including 
the on-screen position, and the selection. Even file searches 
(live updated) are stored as 0 length files with mimetype 
application/x-vnd.Be-query.

I think (X)Emacs could benefit from attribute support.
Possible uses include saving current buffer selection 
(as character range), cursor position, character encoding, 
mimetype (and by extention editing mode), mode options 
(tab-width, ...), ... and I'd prefer it to be cross-platform 
instead of Linux or BeOS-specific. I might ultimately create 
a library to encap various APIs.

I don't know much about POSIX attrs yet, what I know makes me 
think it's not very featureful, but I hope I'm wrong.
The BeOS attributes differ from the POSIX ones on several points.
- they are typed. each attributes carry a 32 bit type, some of 
which are defined by the system:
B_INT64_TYPE = 'LLNG',
B_INT32_TYPE = 'LONG',
B_INT16_TYPE = 'SHRT',
B_INT8_TYPE  = 'BYTE',
B_STRING_TYPE = 'CSTR',
B_MIME_STRING_TYPE = 'MIMS', // used for mime-type
// a lot more ... and applications are free to use their own 
types (4 caps are reserved for the system).
Note the type, even if required by read_attr(), is not part of 
the key, and the filesystem can only have a single attribute 
for the same file and name. (actually I believe it's up to the 
filesystem kernel addon). So it is easy to emulate the BeOS API 
from the POSIX one using 4 bytes at the start of the data, though 
it might not be the cleanest way. Another option is to treat POSIX 
attrs as strings, and use them with data like "int(3)", "str(foo)"...
- they are indexable (at least those of generic types, it's up to 
the underlying filesystem)
- they are queryable (those indexed), the filesystem kernel addon 
answers the query directly.
- the API (see later) works on file descriptors, while the posix 
API seems to work on paths. I feel the former is more logical, for 
example it works even if someone is mv-ing the file and other stuff, 
besides it's called "extended _file_ attribute" (a directory being 
just a weird file), and not a _path_ attribute. I think that point 
isn't much of a problem, it's easy to get an fd from a path anyway :) 
(for folders, the DIR struct has an fd field).

I don't think Emacs really needs query support 
(though it could be funny), so it should be possible to find a common 
denominator.
I think OS/2 has some form of attribute support too in HPFS, but 
I don't know what kind. I don't know what NTFS is up to, appart 
the ugly "file forks" stuff. I'll ask around about HFS+.

Has anyone attempted to add attribute support to XEmacs already ?
Any comment ?

Cheers,
François.

Here is how the C level API looks (the higher level is exposed 
as methods on the BEntry class, which BFile, BDirectory and 
BSymLink inherit from):
ssize_t fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos, void *buf, size_t count);
ssize_t fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos, const void *buf, size_t count);
int fs_remove_attr(int fd, const char *attr);

DIR *      fs_open_attr_dir(const char *path);
DIR *      fs_fopen_attr_dir(int fd);
int                fs_close_attr_dir(DIR *dirp);
struct dirent *fs_read_attr_dir(DIR *dirp);
void       fs_rewind_attr_dir(DIR *dirp);

typedef struct attr_info
{
        uint32     type;
        off_t      size;
} attr_info;
int fs_stat_attr(int fd, const char *name, struct attr_info *ai);