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, |