Re: [PATCH] Posix file attribute support on VFAT (take #2)

From: roucaries bastien
Date: Mon Aug 22 2005 - 21:00:54 EST


On 8/22/05, Pavel Machek <pavel@xxxxxx> wrote:
> Hi!
>
> > > This is a take 2 of posix file attribute support on VFAT.
> >
> > Sorry, but this is far too scary. Please just use one of the sane
> > filesystems linux supports.
>
> Unfortunately, it makes sense. If you have compact flash card, you
> really want to have VFAT there, so that it is a) compatible with
> windows and b) so that you don't kill the hardware.

Why not using fuse in a initramfs?

Why not doing this with fuse? Write a filesystem that will use the
base fat file system (or any other stupid file system) but using a
database (BSD) or a file for non existent field. This new layer will
implement:
o mapping between true name and short name
o links (soft and emulated hard)
o permissions (and special files)

This solution is more general and can apply to all the stupid filesystems.
In the initramfs we need only to put:
o fuse module
o our fuse filesystem statically linked or again klibc.

Moreover this doesn't add more fat (fat because previous solution is
really ugly) to the kernel and will implement an universal umsdos.

I believe a shell program example will give you a better idea of my minds:
-----
modprobe fuse
mount -t vfat /dev/hda1 /mnt
# fuse filesystem use the old /mnt
# It do a chdir in /mnt (base) before the mount was efective
mount -t fuse_extenddumbfilesystem none /mnt -o base=/mnt
# chroot
chroot /mnt
-------

But some could object that fuse like a support of write shared memory
mmaped segment, but it is not different than nfs root!

Slowness is not a valid argument because fat and other file system are
not really suitable for unix computing...

I join as an attachment (I know, it is not really good), my 1c simple
implementation of such filesystem. This program do only the fuse bind
mount nothing else but if somebody want to go further...

> I guess being able to use CF card for root filesystem is usefull,
> too....
>
> Pavel
> --
> if you have sharp zaurus hardware you don't need... you know my address
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2005 Miklos Szeredi <miklos@xxxxxxxxxx>

This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/

//#include <config.h>

//#ifdef linux
/* For pread()/pwrite() */
#define _XOPEN_SOURCE 500
#define FUSE_USE_VERSION 22
#define _FILE_OFFSET_BITS 64
//#endif

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/statfs.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif

/*
* remove the absolute path part
*/
static char *local=".";
static inline const char *rel(const char *path)
{
if(strcmp(path,"/")==0)
return local;
else
return (path+1);
}


static int xmp_getattr(const char *path, struct stat *stbuf)
{
int res;

res = lstat(rel(path), stbuf);
if(res == -1)
return -errno;

return 0;
}

static int xmp_readlink(const char *path, char *buf, size_t size)
{
int res;

res = readlink(rel(path), buf, size - 1);

if(res == -1)
return -errno;

buf[res] = '\0';
return 0;
}


static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
DIR *dp;
struct dirent *de;

(void) offset;
(void) fi;

dp = opendir(rel(path));
if(dp == NULL)
return -errno;

while((de = readdir(dp)) != NULL) {
struct stat st;
memset(&st, 0, sizeof(st));
st.st_ino = de->d_ino;
st.st_mode = de->d_type << 12;
if (filler(buf, de->d_name, &st, 0))
break;
}

closedir(dp);
return 0;
}

static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
int res;

res = mknod(rel(path), mode, rdev);
if(res == -1)
return -errno;

return 0;
}

static int xmp_mkdir(const char *path, mode_t mode)
{
int res;

res = mkdir(rel(path), mode);
if(res == -1)
return -errno;

return 0;
}

static int xmp_unlink(const char *path)
{
int res;

res = unlink(rel(path));
if(res == -1)
return -errno;

return 0;
}

static int xmp_rmdir(const char *path)
{
int res;

res = rmdir(rel(path));
if(res == -1)
return -errno;

return 0;
}

static int xmp_symlink(const char *from, const char *to)
{
int res;

res = symlink(rel(from), to);
if(res == -1)
return -errno;

return 0;
}

static int xmp_rename(const char *from, const char *to)
{
int res;

res = rename(rel(from), rel(to));
if(res == -1)
return -errno;

return 0;
}

static int xmp_link(const char *from, const char *to)
{
int res;

res = link(rel(from), rel(to));
if(res == -1)
return -errno;

return 0;
}

static int xmp_chmod(const char *path, mode_t mode)
{
int res;

res = chmod(rel(path), mode);
if(res == -1)
return -errno;

return 0;
}

static int xmp_chown(const char *path, uid_t uid, gid_t gid)
{
int res;

res = lchown(rel(path), uid, gid);
if(res == -1)
return -errno;

return 0;
}

static int xmp_truncate(const char *path, off_t size)
{
int res;

res = truncate(rel(path), size);
if(res == -1)
return -errno;

return 0;
}

static int xmp_utime(const char *path, struct utimbuf *buf)
{
int res;

res = utime(rel(path), buf);
if(res == -1)
return -errno;

return 0;
}


static int xmp_open(const char *path, struct fuse_file_info *fi)
{
int res;

res = open(rel(path), fi->flags);
if(res == -1)
return -errno;

close(res);
return 0;
}

static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
int fd;
int res;

(void) fi;
fd = open(rel(path), O_RDONLY);
if(fd == -1)
return -errno;

res = pread(fd, buf, size, offset);
if(res == -1)
res = -errno;

close(fd);
return res;
}

static int xmp_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int fd;
int res;

(void) fi;
fd = open(rel(path), O_WRONLY);
if(fd == -1)
return -errno;

res = pwrite(fd, buf, size, offset);
if(res == -1)
res = -errno;

close(fd);
return res;
}

static int xmp_statfs(const char *path, struct statfs *stbuf)
{
int res;

res = statfs(rel(path), stbuf);
if(res == -1)
return -errno;

return 0;
}

static int xmp_release(const char *path, struct fuse_file_info *fi)
{
/* Just a stub. This method is optional and can safely be left
unimplemented */

(void) path;
(void) fi;
return 0;
}

static int xmp_fsync(const char *path, int isdatasync,
struct fuse_file_info *fi)
{
/* Just a stub. This method is optional and can safely be left
unimplemented */

(void) path;
(void) isdatasync;
(void) fi;
return 0;
}

#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int xmp_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags)
{
int res = lsetxattr(rel(path), name, value, size, flags);
if(res == -1)
return -errno;
return 0;
}

static int xmp_getxattr(const char *path, const char *name, char *value,
size_t size)
{
int res = lgetxattr(rel(path), name, value, size);
if(res == -1)
return -errno;
return res;
}

static int xmp_listxattr(const char *path, char *list, size_t size)
{
int res = llistxattr(rel(path), list, size);
if(res == -1)
return -errno;
return res;
}

static int xmp_removexattr(const char *path, const char *name)
{
int res = lremovexattr(rel(path), name);
if(res == -1)
return -errno;
return 0;
}
#endif /* HAVE_SETXATTR */

static struct fuse_operations xmp_oper = {
.getattr = xmp_getattr,
.readlink = xmp_readlink,
.readdir = xmp_readdir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.link = xmp_link,
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
.utime = xmp_utime,
.open = xmp_open,
.read = xmp_read,
.write = xmp_write,
.statfs = xmp_statfs,
.release = xmp_release,
.fsync = xmp_fsync,
#ifdef HAVE_SETXATTR
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
.listxattr = xmp_listxattr,
.removexattr= xmp_removexattr,
#endif
};

int main(int argc, char *argv[])
{
chdir(argv[argc-1]);
return fuse_main(argc-1, argv, &xmp_oper);
}