From: Miklos S. <mi...@sz...> - 2009-02-23 10:39:05
|
This patch adds the hard link extension to sshfs. Index: sshfs/sshfs.c =================================================================== --- sshfs.orig/sshfs.c 2009-02-12 13:37:46.000000000 +0100 +++ sshfs/sshfs.c 2009-02-20 20:10:09.000000000 +0100 @@ -107,6 +107,7 @@ #define SFTP_EXT_POSIX_RENAME "pos...@op..." #define SFTP_EXT_STATVFS "st...@op..." +#define SFTP_EXT_LINK "li...@op..." #define PROTO_VERSION 3 @@ -219,6 +220,7 @@ struct sshfs { char *password; int ext_posix_rename; int ext_statvfs; + int ext_link; /* statistics */ uint64_t bytes_sent; @@ -1358,6 +1360,9 @@ static int sftp_init_reply_ok(struct buf if (strcmp(ext, SFTP_EXT_STATVFS) == 0 && strcmp(extdata, "2") == 0) sshfs.ext_statvfs = 1; + if (strcmp(ext, SFTP_EXT_LINK) == 0 && + strcmp(extdata, "1") == 0) + sshfs.ext_link = 1; } while (buf2.len < buf2.size); } return 0; @@ -2050,6 +2055,25 @@ static int sshfs_rename(const char *from return err; } +static int sshfs_link(const char *from, const char *to) +{ + int err = -ENOSYS; + + if (sshfs.ext_link) { + struct buffer buf; + + buf_init(&buf, 0); + buf_add_string(&buf, SFTP_EXT_LINK); + buf_add_path(&buf, from); + buf_add_path(&buf, to); + err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS, + NULL); + buf_free(&buf); + } + + return err; +} + static int sshfs_chmod(const char *path, mode_t mode) { int err; @@ -2805,6 +2829,7 @@ static struct fuse_cache_operations sshf .unlink = sshfs_unlink, .rmdir = sshfs_rmdir, .rename = sshfs_rename, + .link = sshfs_link, .chmod = sshfs_chmod, .chown = sshfs_chown, .truncate = sshfs_truncate, |
From: Miklos S. <mi...@sz...> - 2009-02-23 10:41:06
|
This patch adds all the missing commonly used UNIX attributes: st_dev, st_ino, st_nlink, st_rdev, st_blocks, st_blksize, st_ctime. In addition it extends st_atime and st_mtime to 64bits, and adds nanosecond resolution to all three timestamps. Index: sshfs/sshfs.c =================================================================== --- sshfs.orig/sshfs.c 2009-02-12 15:12:54.000000000 +0100 +++ sshfs/sshfs.c 2009-02-20 20:10:06.000000000 +0100 @@ -105,6 +105,20 @@ #define SSH2_FXE_STATVFS_ST_RDONLY 0x00000001 #define SSH2_FXE_STATVFS_ST_NOSUID 0x00000002 +/* ex...@op... extra attribute flags */ +#define SSH2_FXE_EXTATTR_DEV 0x00000001 +#define SSH2_FXE_EXTATTR_INO 0x00000002 +#define SSH2_FXE_EXTATTR_NLINK 0x00000004 +#define SSH2_FXE_EXTATTR_RDEV 0x00000008 +#define SSH2_FXE_EXTATTR_BLKSIZE 0x00000010 +#define SSH2_FXE_EXTATTR_BLOCKS 0x00000020 +#define SSH2_FXE_EXTATTR_ATIME 0x00000040 +#define SSH2_FXE_EXTATTR_ATIMENSEC 0x00000080 +#define SSH2_FXE_EXTATTR_MTIME 0x00000100 +#define SSH2_FXE_EXTATTR_MTIMENSEC 0x00000200 +#define SSH2_FXE_EXTATTR_CTIME 0x00000400 +#define SSH2_FXE_EXTATTR_CTIMENSEC 0x00000800 + #define SFTP_EXT_POSIX_RENAME "pos...@op..." #define SFTP_EXT_STATVFS "st...@op..." #define SFTP_EXT_LINK "li...@op..." @@ -598,6 +612,78 @@ static inline int buf_get_string(struct return 0; } +static int buf_get_extattr(struct buffer *buf, struct stat *stbuf) +{ + uint32_t flags; + uint32_t val32; + uint64_t val64; + + if (buf_get_uint32(buf, &flags) == -1) + return -1; + if (flags & SSH2_FXE_EXTATTR_DEV) { + if (buf_get_uint64(buf, &val64) == -1) + return -1; + stbuf->st_dev = val64; + } + if (flags & SSH2_FXE_EXTATTR_INO) { + if (buf_get_uint64(buf, &val64) == -1) + return -1; + stbuf->st_ino = val64; + } + if (flags & SSH2_FXE_EXTATTR_NLINK) { + if (buf_get_uint32(buf, &val32) == -1) + return -1; + stbuf->st_nlink = val32; + } + if (flags & SSH2_FXE_EXTATTR_RDEV) { + if (buf_get_uint64(buf, &val64) == -1) + return -1; + stbuf->st_rdev = val64; + } + if (flags & SSH2_FXE_EXTATTR_BLKSIZE) { + if (buf_get_uint32(buf, &val32) == -1) + return -1; + stbuf->st_blksize = val32; + } + if (flags & SSH2_FXE_EXTATTR_BLOCKS) { + if (buf_get_uint64(buf, &val64) == -1) + return -1; + stbuf->st_blocks = val64; + } + if (flags & SSH2_FXE_EXTATTR_ATIME) { + if (buf_get_uint64(buf, &val64) == -1) + return -1; + stbuf->st_atime = val64; + } + if (flags & SSH2_FXE_EXTATTR_ATIMENSEC) { + if (buf_get_uint32(buf, &val32) == -1) + return -1; + stbuf->st_atim.tv_nsec = val32; + } + if (flags & SSH2_FXE_EXTATTR_MTIME) { + if (buf_get_uint64(buf, &val64) == -1) + return -1; + stbuf->st_mtime = val64; + } + if (flags & SSH2_FXE_EXTATTR_MTIMENSEC) { + if (buf_get_uint32(buf, &val32) == -1) + return -1; + stbuf->st_mtim.tv_nsec = val32; + } + if (flags & SSH2_FXE_EXTATTR_CTIME) { + if (buf_get_uint64(buf, &val64) == -1) + return -1; + stbuf->st_ctime = val64; + } + if (flags & SSH2_FXE_EXTATTR_CTIMENSEC) { + if (buf_get_uint32(buf, &val32) == -1) + return -1; + stbuf->st_ctim.tv_nsec = val32; + } + + return 0; +} + static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp) { uint32_t flags; @@ -627,24 +713,6 @@ static int buf_get_attrs(struct buffer * buf_get_uint32(buf, &mtime) == -1) return -1; } - if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) { - uint32_t extcount; - unsigned i; - if (buf_get_uint32(buf, &extcount) == -1) - return -1; - for (i = 0; i < extcount; i++) { - struct buffer tmp; - if (buf_get_data(buf, &tmp) == -1) - return -1; - buf_free(&tmp); - if (buf_get_data(buf, &tmp) == -1) - return -1; - buf_free(&tmp); - } - } - - if (sshfs.remote_uid_detected && uid == sshfs.remote_uid) - uid = sshfs.local_uid; memset(stbuf, 0, sizeof(struct stat)); stbuf->st_mode = mode; @@ -659,6 +727,34 @@ static int buf_get_attrs(struct buffer * stbuf->st_gid = gid; stbuf->st_atime = atime; stbuf->st_ctime = stbuf->st_mtime = mtime; + + if (sshfs.remote_uid_detected && uid == sshfs.remote_uid) + uid = sshfs.local_uid; + + if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) { + uint32_t extcount; + unsigned i; + if (buf_get_uint32(buf, &extcount) == -1) + return -1; + for (i = 0; i < extcount; i++) { + char *type; + struct buffer data; + int err = -1; + + if (buf_get_string(buf, &type) == -1) + return -1; + if (buf_get_data(buf, &data) != -1) { + err = 0; + if (strcmp(type, "ex...@op...") == 0) + err = buf_get_extattr(&data, stbuf); + buf_free(&data); + } + free(type); + if (err) + return err; + } + } + return 0; } @@ -1606,7 +1702,7 @@ static int start_processing_thread(void) #if FUSE_VERSION >= 26 static void *sshfs_init(struct fuse_conn_info *conn) #else - static void *sshfs_init(void) +static void *sshfs_init(void) #endif { #if FUSE_VERSION >= 26 Index: sshfs/cache.c =================================================================== --- sshfs.orig/cache.c 2009-02-12 13:37:46.000000000 +0100 +++ sshfs/cache.c 2009-02-12 15:12:54.000000000 +0100 @@ -33,10 +33,16 @@ struct cache { static struct cache cache; +struct direntry { + ino_t ino; + mode_t type; + char name[0]; +}; + struct node { struct stat stat; time_t stat_valid; - char **dir; + struct direntry **dir; time_t dir_valid; char *link; time_t link_valid; @@ -51,10 +57,22 @@ struct fuse_cache_dirhandle { uint64_t wrctr; }; +static void free_dir(struct direntry **dir) +{ + if (dir != NULL) { + struct direntry **d; + + for (d = dir; *d != NULL; d++) + g_free(*d); + + g_free(dir); + } +} + static void free_node(gpointer node_) { struct node *node = (struct node *) node_; - g_strfreev(node->dir); + free_dir(node->dir); g_free(node); } @@ -182,7 +200,7 @@ void cache_add_attr(const char *path, co pthread_mutex_unlock(&cache.lock); } -static void cache_add_dir(const char *path, char **dir) +static void cache_add_dir(const char *path, struct direntry **dir) { struct node *node; time_t now; @@ -190,7 +208,7 @@ static void cache_add_dir(const char *pa pthread_mutex_lock(&cache.lock); node = cache_get(path); now = time(NULL); - g_strfreev(node->dir); + free_dir(node->dir); node->dir = dir; node->dir_valid = time(NULL) + cache.dir_timeout; if (node->dir_valid > node->valid) @@ -290,9 +308,15 @@ static int cache_readlink(const char *pa static int cache_dirfill(fuse_cache_dirh_t ch, const char *name, const struct stat *stbuf) { - int err = ch->filler(ch->h, name, 0, 0); + int err = ch->filler(ch->h, name, stbuf->st_mode >> 12, stbuf->st_ino); if (!err) { - g_ptr_array_add(ch->dir, g_strdup(name)); + struct direntry *de; + + de = g_malloc(sizeof(struct direntry) + strlen(name) + 1); + de->ino = stbuf->st_ino; + de->type = stbuf->st_mode >> 12; + strcpy(de->name, name); + g_ptr_array_add(ch->dir, de); if (stbuf->st_mode & S_IFMT) { char *fullpath; const char *basepath = !ch->path[1] ? "" : ch->path; @@ -309,7 +333,7 @@ static int cache_getdir(const char *path { struct fuse_cache_dirhandle ch; int err; - char **dir; + struct direntry **dir; struct node *node; pthread_mutex_lock(&cache.lock); @@ -317,8 +341,10 @@ static int cache_getdir(const char *path if (node != NULL && node->dir != NULL) { time_t now = time(NULL); if (node->dir_valid - now >= 0) { - for(dir = node->dir; *dir != NULL; dir++) - filler(h, *dir, 0, 0); + for(dir = node->dir; *dir != NULL; dir++) { + struct direntry *de = *dir; + filler(h, de->name, de->type, de->ino); + } pthread_mutex_unlock(&cache.lock); return 0; } @@ -332,11 +358,11 @@ static int cache_getdir(const char *path ch.wrctr = cache_get_write_ctr(); err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill); g_ptr_array_add(ch.dir, NULL); - dir = (char **) ch.dir->pdata; + dir = (struct direntry **) ch.dir->pdata; if (!err) cache_add_dir(path, dir); else - g_strfreev(dir); + free_dir(dir); g_ptr_array_free(ch.dir, FALSE); return err; } @@ -344,8 +370,7 @@ static int cache_getdir(const char *path static int cache_unity_dirfill(fuse_cache_dirh_t ch, const char *name, const struct stat *stbuf) { - (void) stbuf; - return ch->filler(ch->h, name, 0, 0); + return ch->filler(ch->h, name, stbuf->st_mode >> 12, stbuf->st_ino); } static int cache_unity_getdir(const char *path, fuse_dirh_t h, |
From: Miklos S. <mi...@sz...> - 2009-02-23 10:43:01
|
This patch adds support for the "attrconfig" extension to sshfs. Index: sshfs/sshfs.c =================================================================== --- sshfs.orig/sshfs.c 2009-02-12 15:13:07.000000000 +0100 +++ sshfs/sshfs.c 2009-02-12 16:01:10.000000000 +0100 @@ -119,9 +119,13 @@ #define SSH2_FXE_EXTATTR_CTIME 0x00000400 #define SSH2_FXE_EXTATTR_CTIMENSEC 0x00000800 +/* att...@op... flags */ +#define SSH2_FXE_ATTRCONFIG_NOLONGNAME 0x00000001 + #define SFTP_EXT_POSIX_RENAME "pos...@op..." #define SFTP_EXT_STATVFS "st...@op..." #define SFTP_EXT_LINK "li...@op..." +#define SFTP_EXT_ATTRCONFIG "att...@op..." #define PROTO_VERSION 3 @@ -235,6 +239,7 @@ struct sshfs { int ext_posix_rename; int ext_statvfs; int ext_link; + int ext_attrconfig; /* statistics */ uint64_t bytes_sent; @@ -1409,6 +1414,82 @@ static void *process_requests(void *data return NULL; } +static void sftp_attrconfig(void) +{ + uint32_t id = sftp_get_id(); + uint32_t replid; + uint8_t type; + struct buffer buf; + struct iovec iov[1]; + uint32_t attr_mask = + SSH_FILEXFER_ATTR_SIZE | + SSH_FILEXFER_ATTR_UIDGID | + SSH_FILEXFER_ATTR_PERMISSIONS | + SSH_FILEXFER_ATTR_ACMODTIME; + uint32_t ext_attr_mask = + SSH2_FXE_EXTATTR_DEV | + SSH2_FXE_EXTATTR_INO | + SSH2_FXE_EXTATTR_NLINK | + SSH2_FXE_EXTATTR_RDEV | + SSH2_FXE_EXTATTR_BLKSIZE | + SSH2_FXE_EXTATTR_BLOCKS | + SSH2_FXE_EXTATTR_ATIME | + SSH2_FXE_EXTATTR_ATIMENSEC | + SSH2_FXE_EXTATTR_MTIME | + SSH2_FXE_EXTATTR_MTIMENSEC | + SSH2_FXE_EXTATTR_CTIME | + SSH2_FXE_EXTATTR_CTIMENSEC; + uint32_t dir_attr_mask = attr_mask; + uint32_t dir_ext_attr_mask = ext_attr_mask; + uint32_t flags = SSH2_FXE_ATTRCONFIG_NOLONGNAME; + + buf_init(&buf, 0); + buf_add_string(&buf, SFTP_EXT_ATTRCONFIG); + buf_add_uint32(&buf, flags); + buf_add_uint32(&buf, attr_mask); + buf_add_uint32(&buf, ext_attr_mask); + buf_add_uint32(&buf, dir_attr_mask); + buf_add_uint32(&buf, dir_ext_attr_mask); + buf_to_iov(&buf, &iov[0]); + if (sftp_send_iov(SSH_FXP_EXTENDED, id, iov, 1) == -1) + goto out; + buf_clear(&buf); + if (sftp_read(&type, &buf) == -1) + goto out; + if (type != SSH_FXP_EXTENDED_REPLY && type != SSH_FXP_STATUS) { + fprintf(stderr, "protocol error\n"); + goto out; + } + if (buf_get_uint32(&buf, &replid) == -1) + goto out; + if (replid != id) { + fprintf(stderr, "bad reply ID\n"); + goto out; + } + if (type == SSH_FXP_STATUS) { + uint32_t serr; + if (buf_get_uint32(&buf, &serr) == -1) + goto out; + + fprintf(stderr, "attrconfig failed: %i\n", serr); + goto out; + } + if (buf_get_uint32(&buf, &flags) == -1 || + buf_get_uint32(&buf, &attr_mask) == -1 || + buf_get_uint32(&buf, &ext_attr_mask) == -1 || + buf_get_uint32(&buf, &dir_attr_mask) == -1 || + buf_get_uint32(&buf, &dir_ext_attr_mask) == -1) + goto out; + + DEBUG("attrconfig: flags: 0x%08x attr mask: 0x%08x ext mask: 0x%08x\n", + flags, attr_mask, ext_attr_mask); + DEBUG("attrconfig: dir attr mask: 0x%08x ext mask: 0x%08x\n", + dir_attr_mask, dir_ext_attr_mask); + +out: + buf_free(&buf); +} + static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version) { uint32_t len; @@ -1459,6 +1540,9 @@ static int sftp_init_reply_ok(struct buf if (strcmp(ext, SFTP_EXT_LINK) == 0 && strcmp(extdata, "1") == 0) sshfs.ext_link = 1; + if (strcmp(ext, SFTP_EXT_ATTRCONFIG) == 0 && + strcmp(extdata, "1") == 0) + sshfs.ext_attrconfig = 1; } while (buf2.len < buf2.size); } return 0; @@ -1512,6 +1596,8 @@ static int sftp_init() version, PROTO_VERSION); } res = 0; + if (sshfs.ext_attrconfig) + sftp_attrconfig(); out: buf_free(&buf); |