</varlistentry>
+ <varlistentry>
+ <term>gpfs:clamp_invalid_times = [ yes | no ]</term>
+ <listitem>
+ <para>
+ GPFS stores timestamps using 32-bit unsigned integers for the
+ seconds component. When using gpfs:settimes = yes, this module
+ validates times that clients attempt to set are within the
+ supported GPFS range between 0 and UINT32_MAX. If a timestamp is
+ outside of this range, the client request is rejected. To cope
+ with clients setting eg temporary timestamps outside the valid
+ range, this parameter can be used to clamp the client timestamp
+ to the allowed range. Times before Thu Jan 1 12:00:00 AM UTC
+ 1970 (the UNIX epock) are then set to Thu Jan 1 12:00:00 AM UTC
+ 1970, times after Sun Feb 7 06:28:15 AM UTC 2106 will be set to
+ Sun Feb 7 06:28:15 AM UTC 2106.
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ <command>no(default)</command> - Fail request with invalid time.
+ </para></listitem>
+ <listitem><para>
+ <command>yes</command> - clamp invalid times to 0 or UINT32_MAX.
+ </para></listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry>
<term>gpfs:syncio = [yes|no]</term>
<listitem>
bool acl;
bool settimes;
bool recalls;
+ bool clamp_invalid_times;
struct {
bool gpfs_fstat_x;
} pathref_ok;
return NT_STATUS_OK;
}
-static int timespec_to_gpfs_time(
- struct timespec ts, gpfs_timestruc_t *gt, int idx, int *flags)
+static int timespec_to_gpfs_time(struct gpfs_config_data *config,
+ struct timespec ts,
+ gpfs_timestruc_t *gt,
+ int idx,
+ int *flags)
{
if (is_omit_timespec(&ts)) {
return 0;
}
if (ts.tv_sec < 0 || ts.tv_sec > UINT32_MAX) {
- DBG_NOTICE("GPFS uses 32-bit unsigned timestamps "
- "and cannot handle %jd.\n",
- (intmax_t)ts.tv_sec);
- errno = ERANGE;
- return -1;
+ if (!config->clamp_invalid_times) {
+ DBG_NOTICE("GPFS uses 32-bit unsigned timestamps "
+ "and cannot handle %jd.\n",
+ (intmax_t)ts.tv_sec);
+ errno = ERANGE;
+ return -1;
+ }
+ if (ts.tv_sec < 0) {
+ ts.tv_sec = 0;
+ } else {
+ ts.tv_sec = UINT32_MAX;
+ }
}
*flags |= 1 << idx;
return 0;
}
-static int smbd_gpfs_set_times(struct files_struct *fsp,
+static int smbd_gpfs_set_times(struct gpfs_config_data *config,
+ struct files_struct *fsp,
struct smb_file_time *ft)
{
gpfs_timestruc_t gpfs_times[4];
int rc;
ZERO_ARRAY(gpfs_times);
- rc = timespec_to_gpfs_time(ft->atime, gpfs_times, 0, &flags);
+ rc = timespec_to_gpfs_time(config, ft->atime, gpfs_times, 0, &flags);
if (rc != 0) {
return rc;
}
- rc = timespec_to_gpfs_time(ft->mtime, gpfs_times, 1, &flags);
+ rc = timespec_to_gpfs_time(config, ft->mtime, gpfs_times, 1, &flags);
if (rc != 0) {
return rc;
}
/* No good mapping from LastChangeTime to ctime, not storing */
- rc = timespec_to_gpfs_time(ft->create_time, gpfs_times, 3, &flags);
+ rc = timespec_to_gpfs_time(config,
+ ft->create_time,
+ gpfs_times,
+ 3,
+ &flags);
if (rc != 0) {
return rc;
}
/* Try to use gpfs_set_times if it is enabled and available */
if (config->settimes) {
- return smbd_gpfs_set_times(fsp, ft);
+ return smbd_gpfs_set_times(config, fsp, ft);
}
DBG_DEBUG("gpfs_set_times() not available or disabled, "
config->recalls = lp_parm_bool(SNUM(handle->conn), "gpfs",
"recalls", true);
+ config->clamp_invalid_times = lp_parm_bool(SNUM(handle->conn), "gpfs",
+ "clamp_invalid_times", false);
+
ret = vfs_gpfs_check_pathref(config, handle->conn);
if (ret != 0) {
DBG_ERR("vfs_gpfs_check_pathref() on [%s] failed\n",