From 5d070483acf527ca20910c83d4735e1f99c32e24 Mon Sep 17 00:00:00 2001 From: todd stecher Date: Thu, 29 Jan 2009 08:08:35 -0800 Subject: s3 OneFS: Fake Timestamps This checkin enables setting arbitrary timestamps on files matching the pattern stored in smb.conf. This was a customer request for a specific workflow. Changes include: 1) configuration state machine to avoid tons of string comparisons on each and every stat. 2) Code to adjust post-stat() times to match time now, or sloptime + time now. --- source3/modules/onefs.h | 58 ++++++++++++++++++++ source3/modules/onefs_streams.c | 84 ++++++++++++++++++++++++----- source3/modules/vfs_onefs.c | 114 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+), 14 deletions(-) diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index 9c1c1647ba..2044ebec48 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -53,6 +53,62 @@ enum onefs_acl_wire_format #define PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT NULL #define PARM_IGNORE_SACL "ignore sacl" #define PARM_IGNORE_SACL_DEFAULT false +#define PARM_ATIME_NOW "atime now files" +#define PARM_ATIME_SLOP "atime now slop" +#define PARM_CTIME_NOW "ctime now files" +#define PARM_CTIME_SLOP "ctime now slop" +#define PARM_MTIME_NOW "mtime now files" +#define PARM_MTIME_SLOP "mtime now slop" +#define PARM_MTIME_STATIC "mtime static files" +#define PARM_ATIME_STATIC "atime static files" + +#define IS_CTIME_NOW_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ + (cfg)->ctime_now_list,(conn)->case_sensitive)) +#define IS_MTIME_NOW_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ + (cfg)->mtime_now_list,(conn)->case_sensitive)) +#define IS_ATIME_NOW_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ + (cfg)->atime_now_list,(conn)->case_sensitive)) +#define IS_MTIME_STATIC_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ + (cfg)->mtime_static_list,(conn)->case_sensitive)) +#define IS_ATIME_STATIC_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ + (cfg)->atime_static_list,(conn)->case_sensitive)) + +/* + * Store some commonly evaluated parameters to avoid loadparm pain. + */ + +#define ONEFS_VFS_CONFIG_INITIALIZED 0x00010000 + +#define ONEFS_VFS_CONFIG_FAKETIMESTAMPS 0x00000001 + + +struct onefs_vfs_config +{ + int32 init_flags; + + /* data for fake timestamps */ + int atime_slop; + int ctime_slop; + int mtime_slop; + + /* Per-share list of files to fake the create time for. */ + name_compare_entry *ctime_now_list; + + /* Per-share list of files to fake the modification time for. */ + name_compare_entry *mtime_now_list; + + /* Per-share list of files to fake the access time for. */ + name_compare_entry *atime_now_list; + + /* Per-share list of files to fake the modification time for. */ + name_compare_entry *mtime_static_list; + + /* The access time will equal the create time. */ + /* The modification time will equal the create time.*/ + + /* Per-share list of files to fake the access time for. */ + name_compare_entry *atime_static_list; +}; /* * vfs interface handlers @@ -121,6 +177,8 @@ NTSTATUS onefs_samba_sd_to_sd(uint32 security_info_sent, SEC_DESC *psd, NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname, char **pbase, char **pstream); +bool onefs_get_config(int snum, int config_type, + struct onefs_vfs_config *cfg); /* * System Interfaces */ diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c index 78b0fd61bf..615edf379d 100644 --- a/source3/modules/onefs_streams.c +++ b/source3/modules/onefs_streams.c @@ -216,6 +216,58 @@ static void merge_stat(SMB_STRUCT_STAT *stream_sbuf, stream_sbuf->st_flags |= base_sbuf->st_flags & dos_flags; } +/* fake timestamps */ +static void onefs_adjust_stat_time(vfs_handle_struct *handle, const char *fname, + SMB_STRUCT_STAT *sbuf) +{ + struct onefs_vfs_config cfg; + struct timeval tv_now = {0, 0}; + bool static_mtime = False; + bool static_atime = False; + + if (!onefs_get_config(SNUM(handle->conn), + ONEFS_VFS_CONFIG_FAKETIMESTAMPS, &cfg)) { + return; + } + + if (IS_MTIME_STATIC_PATH(handle->conn, &cfg, fname)) { + sbuf->st_mtime = sbuf->st_birthtime; + static_mtime = True; + } + if (IS_ATIME_STATIC_PATH(handle->conn, &cfg, fname)) { + sbuf->st_atime = sbuf->st_birthtime; + static_atime = True; + } + + if (IS_CTIME_NOW_PATH(handle->conn, &cfg, fname)) { + if (cfg.ctime_slop < 0) { + sbuf->st_birthtime = INT_MAX - 1; + } else { + GetTimeOfDay(&tv_now); + sbuf->st_birthtime = tv_now.tv_sec + cfg.ctime_slop; + } + } + + if (!static_mtime && IS_MTIME_NOW_PATH(handle->conn,&cfg,fname)) { + if (cfg.mtime_slop < 0) { + sbuf->st_mtime = INT_MAX - 1; + } else { + if (tv_now.tv_sec == 0) + GetTimeOfDay(&tv_now); + sbuf->st_mtime = tv_now.tv_sec + cfg.mtime_slop; + } + } + if (!static_atime && IS_ATIME_NOW_PATH(handle->conn,&cfg,fname)) { + if (cfg.atime_slop < 0) { + sbuf->st_atime = INT_MAX - 1; + } else { + if (tv_now.tv_sec == 0) + GetTimeOfDay(&tv_now); + sbuf->st_atime = tv_now.tv_sec + cfg.atime_slop; + } + } +} + static int stat_stream(vfs_handle_struct *handle, const char *base, const char *stream, SMB_STRUCT_STAT *sbuf, int flags) { @@ -257,15 +309,16 @@ int onefs_stat(vfs_handle_struct *handle, const char *path, return ret; if (!is_stream) { - return SMB_VFS_NEXT_STAT(handle, path, sbuf); - } - - /* If it's the ::$DATA stream just stat the base file name. */ - if (!stream) { - return SMB_VFS_NEXT_STAT(handle, base, sbuf); + ret = SMB_VFS_NEXT_STAT(handle, path, sbuf); + } else if (!stream) { + /* If it's the ::$DATA stream just stat the base file name. */ + ret = SMB_VFS_NEXT_STAT(handle, base, sbuf); + } else { + ret = stat_stream(handle, base, stream, sbuf, 0); } - return stat_stream(handle, base, stream, sbuf, 0); + onefs_adjust_stat_time(handle, path, sbuf); + return ret; } int onefs_fstat(vfs_handle_struct *handle, struct files_struct *fsp, @@ -288,6 +341,7 @@ int onefs_fstat(vfs_handle_struct *handle, struct files_struct *fsp, } } + onefs_adjust_stat_time(handle, fsp->fsp_name, sbuf); return ret; } @@ -304,15 +358,17 @@ int onefs_lstat(vfs_handle_struct *handle, const char *path, return ret; if (!is_stream) { - return SMB_VFS_NEXT_LSTAT(handle, path, sbuf); - } - - /* If it's the ::$DATA stream just stat the base file name. */ - if (!stream) { - return SMB_VFS_NEXT_LSTAT(handle, base, sbuf); + ret = SMB_VFS_NEXT_LSTAT(handle, path, sbuf); + } else if (!stream) { + /* If it's the ::$DATA stream just stat the base file name. */ + ret = SMB_VFS_NEXT_LSTAT(handle, base, sbuf); + } else { + ret = stat_stream(handle, base, stream, sbuf, + AT_SYMLINK_NOFOLLOW); } - return stat_stream(handle, base, stream, sbuf, AT_SYMLINK_NOFOLLOW); + onefs_adjust_stat_time(handle, path, sbuf); + return ret; } int onefs_unlink(vfs_handle_struct *handle, const char *path) diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index e2f272aa11..1f11f691a4 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -24,6 +24,118 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS +#define ONEFS_DATA_FASTBUF 10 + +struct onefs_vfs_config share_config[ONEFS_DATA_FASTBUF]; +struct onefs_vfs_config *pshare_config; + +static void onefs_load_faketimestamp_config(struct vfs_handle_struct *handle, + struct onefs_vfs_config *cfg) +{ + const char **parm; + int snum = SNUM(handle->conn); + + parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_ATIME_NOW, + NULL); + + if (parm) { + cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; + set_namearray(&cfg->atime_now_list,*parm); + } + + parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_CTIME_NOW, + NULL); + + if (parm) { + cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; + set_namearray(&cfg->ctime_now_list,*parm); + } + + parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_MTIME_NOW, + NULL); + + if (parm) { + cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; + set_namearray(&cfg->mtime_now_list,*parm); + } + + parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_ATIME_STATIC, + NULL); + + if (parm) { + cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; + set_namearray(&cfg->atime_static_list,*parm); + } + + parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_MTIME_STATIC, + NULL); + + if (parm) { + cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; + set_namearray(&cfg->mtime_static_list,*parm); + } + + cfg->atime_slop = lp_parm_int(snum, PARM_ONEFS_TYPE, PARM_ATIME_SLOP,0); + cfg->ctime_slop = lp_parm_int(snum, PARM_ONEFS_TYPE, PARM_CTIME_SLOP,0); + cfg->mtime_slop = lp_parm_int(snum, PARM_ONEFS_TYPE, PARM_MTIME_SLOP,0); +} + + +static int onefs_load_config(struct vfs_handle_struct *handle) +{ + int snum = SNUM(handle->conn); + int share_count = lp_numservices(); + + if (!pshare_config) { + + if (share_count <= ONEFS_DATA_FASTBUF) + pshare_config = share_config; + else { + pshare_config = SMB_MALLOC_ARRAY(struct onefs_vfs_config, + share_count); + if (!pshare_config) { + errno = ENOMEM; + return -1; + } + + memset(pshare_config, 0, + (sizeof(struct onefs_vfs_config) * share_count)); + } + } + + if ((pshare_config[snum].init_flags & + ONEFS_VFS_CONFIG_INITIALIZED) == 0) { + pshare_config[snum].init_flags = + ONEFS_VFS_CONFIG_INITIALIZED; + onefs_load_faketimestamp_config(handle, + &pshare_config[snum]); + } + + return 0; +} + +bool onefs_get_config(int snum, int config_type, + struct onefs_vfs_config *cfg) +{ + if (share_config[snum].init_flags & config_type) + *cfg = share_config[snum]; + else + return false; + + return true; +} + +static int onefs_connect(struct vfs_handle_struct *handle, const char *service, + const char *user) +{ + int ret = onefs_load_config(handle); + + if (ret) + return ret; + + return SMB_VFS_NEXT_CONNECT(handle, service, user); +} + static int onefs_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode) { @@ -130,6 +242,8 @@ static uint32_t onefs_fs_capabilities(struct vfs_handle_struct *handle) } static vfs_op_tuple onefs_ops[] = { + {SMB_VFS_OP(onefs_connect), SMB_VFS_OP_CONNECT, + SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(onefs_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(onefs_mkdir), SMB_VFS_OP_MKDIR, -- cgit