summaryrefslogtreecommitdiff
path: root/source3/smbd/dosmode.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2009-11-17 14:55:02 -0800
committerJeremy Allison <jra@samba.org>2009-11-17 14:55:02 -0800
commita770caed0ff66ddc2d63ac83d20f4cd7fcc2caf5 (patch)
tree479bcb278bcd0ccd20f9506c976d47cb6f41e356 /source3/smbd/dosmode.c
parenta31838eb3c40f4b70c629f94620f435214e414d4 (diff)
downloadsamba-a770caed0ff66ddc2d63ac83d20f4cd7fcc2caf5.tar.gz
samba-a770caed0ff66ddc2d63ac83d20f4cd7fcc2caf5.tar.bz2
samba-a770caed0ff66ddc2d63ac83d20f4cd7fcc2caf5.zip
Remove "store create time" code, cause create time to be stored
in the "user.DOSATTRIB" EA. From the docs: In Samba 3.5.0 and above the "user.DOSATTRIB" extended attribute has been extended to store the create time for a file as well as the DOS attributes. This is done in a backwards compatible way so files created by Samba 3.5.0 and above can still have the DOS attribute read from this extended attribute by earlier versions of Samba, but they will not be able to read the create time stored there. Storing the create time separately from the normal filesystem meta-data allows Samba to faithfully reproduce NTFS semantics on top of a POSIX filesystem. Passes make test but will need more testing. Jeremy.
Diffstat (limited to 'source3/smbd/dosmode.c')
-rw-r--r--source3/smbd/dosmode.c244
1 files changed, 145 insertions, 99 deletions
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index e10f23918d..0f31973675 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -19,6 +19,7 @@
*/
#include "includes.h"
+#include "librpc/gen_ndr/ndr_xattr.h"
static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
{
@@ -205,15 +206,19 @@ static uint32 dos_mode_from_sbuf(connection_struct *conn,
/****************************************************************************
Get DOS attributes from an EA.
+ This can also pull the create time into the stat struct inside smb_fname.
****************************************************************************/
static bool get_ea_dos_attribute(connection_struct *conn,
- const struct smb_filename *smb_fname,
+ struct smb_filename *smb_fname,
uint32 *pattr)
{
+ struct xattr_DOSATTRIB dosattrib;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
ssize_t sizeret;
fstring attrstr;
- unsigned int dosattr;
+ uint32_t dosattr;
if (!lp_store_dos_attributes(SNUM(conn))) {
return False;
@@ -240,18 +245,65 @@ static bool get_ea_dos_attribute(connection_struct *conn,
}
return False;
}
- /* Null terminate string. */
- attrstr[sizeret] = 0;
- DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n",
- smb_fname_str_dbg(smb_fname), attrstr));
- if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
- sscanf(attrstr, "%x", &dosattr) != 1) {
- DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on "
- "file %s - %s\n", smb_fname_str_dbg(smb_fname),
- attrstr));
- return False;
- }
+ blob.data = (uint8_t *)attrstr;
+ blob.length = sizeret;
+
+ ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &dosattrib,
+ (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
+
+ DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
+ smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
+
+ switch (dosattrib.version) {
+ case 0xFFFF:
+ dosattr = dosattrib.info.compatinfoFFFF.attrib;
+ break;
+ case 1:
+ dosattr = dosattrib.info.info1.attrib;
+ if (!null_nttime(dosattrib.info.info1.create_time)) {
+ struct timespec create_time =
+ nt_time_to_unix_timespec(
+ &dosattrib.info.info1.create_time);
+
+ update_stat_ex_create_time(&smb_fname->st,
+ create_time);
+
+ DEBUG(10,("get_ea_dos_attributes: file %s case 1 "
+ "set btime %s\n",
+ smb_fname_str_dbg(smb_fname),
+ time_to_asc(convert_timespec_to_time_t(
+ create_time)) ));
+ }
+ break;
+ case 2:
+ dosattr = dosattrib.info.oldinfo2.attrib;
+ /* Don't know what flags to check for this case. */
+ break;
+ case 3:
+ dosattr = dosattrib.info.info3.attrib;
+ if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
+ !null_nttime(dosattrib.info.info3.create_time)) {
+ struct timespec create_time =
+ nt_time_to_unix_timespec(
+ &dosattrib.info.info3.create_time);
+
+ update_stat_ex_create_time(&smb_fname->st,
+ create_time);
+
+ DEBUG(10,("get_ea_dos_attributes: file %s case 3 "
+ "set btime %s\n",
+ smb_fname_str_dbg(smb_fname),
+ time_to_asc(convert_timespec_to_time_t(
+ create_time)) ));
+ }
+ break;
+ default:
+ DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on "
+ "file %s - %s\n", smb_fname_str_dbg(smb_fname),
+ attrstr));
+ return false;
+ }
if (S_ISDIR(smb_fname->st.st_ex_mode)) {
dosattr |= aDIR;
@@ -273,23 +325,49 @@ static bool get_ea_dos_attribute(connection_struct *conn,
/****************************************************************************
Set DOS attributes in an EA.
+ Also sets the create time.
****************************************************************************/
static bool set_ea_dos_attribute(connection_struct *conn,
struct smb_filename *smb_fname,
uint32 dosmode)
{
- fstring attrstr;
+ struct xattr_DOSATTRIB dosattrib;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
files_struct *fsp = NULL;
- bool ret = False;
+ bool ret = false;
if (!lp_store_dos_attributes(SNUM(conn))) {
return False;
}
- snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
+ ZERO_STRUCT(dosattrib);
+ ZERO_STRUCT(blob);
+
+ dosattrib.version = 3;
+ dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
+ XATTR_DOSINFO_CREATE_TIME;
+ dosattrib.info.info3.attrib = dosmode;
+ unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
+ smb_fname->st.st_ex_btime);
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, talloc_tos(), NULL, &dosattrib,
+ (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
+ ndr_errstr(ndr_err)));
+ return false;
+ }
+
+ if (blob.data == NULL || blob.length == 0) {
+ return false;
+ }
+
if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
- SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr),
+ SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
0) == -1) {
if((errno != EPERM) && (errno != EACCES)) {
if (errno == ENOSYS
@@ -304,7 +382,7 @@ static bool set_ea_dos_attribute(connection_struct *conn,
strerror(errno) ));
set_store_dos_attributes(SNUM(conn), False);
}
- return False;
+ return false;
}
/* We want DOS semantics, ie allow non owner with write permission to change the
@@ -313,7 +391,7 @@ static bool set_ea_dos_attribute(connection_struct *conn,
/* Check if we have write access. */
if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
- return False;
+ return false;
/*
* We need to open the file with write access whilst
@@ -326,17 +404,18 @@ static bool set_ea_dos_attribute(connection_struct *conn,
return ret;
become_root();
if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
- SAMBA_XATTR_DOS_ATTRIB, attrstr,
- strlen(attrstr), 0) == 0) {
- ret = True;
+ SAMBA_XATTR_DOS_ATTRIB, blob.data,
+ blob.length, 0) == 0) {
+ ret = true;
}
unbecome_root();
close_file_fchmod(NULL, fsp);
return ret;
}
- DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr,
- smb_fname_str_dbg(smb_fname)));
- return True;
+ DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
+ (unsigned int)dosmode,
+ smb_fname_str_dbg(smb_fname)));
+ return true;
}
/****************************************************************************
@@ -510,11 +589,12 @@ static bool set_stat_dos_flags(connection_struct *conn,
/****************************************************************************
Change a unix mode to a dos mode.
+ May also read the create timespec into the stat struct in smb_fname
+ if "store dos attributes" is true.
****************************************************************************/
-uint32 dos_mode(connection_struct *conn, const struct smb_filename *smb_fname)
+uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
{
- SMB_STRUCT_STAT sbuf;
uint32 result = 0;
bool offline, used_stat_dos_flags = false;
@@ -553,9 +633,8 @@ uint32 dos_mode(connection_struct *conn, const struct smb_filename *smb_fname)
}
}
- sbuf = smb_fname->st;
- offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &sbuf);
- if (S_ISREG(sbuf.st_ex_mode) && offline) {
+ offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &smb_fname->st);
+ if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
result |= FILE_ATTRIBUTE_OFFLINE;
}
@@ -588,6 +667,9 @@ uint32 dos_mode(connection_struct *conn, const struct smb_filename *smb_fname)
/*******************************************************************
chmod a file - but preserve some bits.
+ If "store dos attributes" is also set it will store the create time
+ from the stat struct in smb_fname (in NTTIME format) in the EA
+ attribute also.
********************************************************************/
int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
@@ -598,6 +680,7 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
mode_t unixmode;
int ret = -1, lret = -1;
uint32_t old_mode;
+ struct timespec new_create_timespec;
/* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
@@ -605,11 +688,6 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
dosmode, smb_fname_str_dbg(smb_fname)));
- if (!VALID_STAT(smb_fname->st)) {
- if (SMB_VFS_STAT(conn, smb_fname))
- return(-1);
- }
-
unixmode = smb_fname->st.st_ex_mode;
get_acl_group_bits(conn, smb_fname->base_name,
@@ -620,6 +698,8 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
else
dosmode &= ~aDIR;
+ new_create_timespec = smb_fname->st.st_ex_btime;
+
old_mode = dos_mode(conn, smb_fname);
if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
@@ -639,11 +719,15 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
- if (old_mode == dosmode) {
+ if (old_mode == dosmode &&
+ (timespec_compare(&new_create_timespec,
+ &smb_fname->st.st_ex_btime) == 0)) {
smb_fname->st.st_ex_mode = unixmode;
return(0);
}
+ smb_fname->st.st_ex_btime = new_create_timespec;
+
#ifdef HAVE_STAT_DOS_FLAGS
{
bool attributes_changed;
@@ -842,6 +926,10 @@ bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
{
+ if (null_timespec(mtime)) {
+ return true;
+ }
+
fsp->write_time_forced = true;
TALLOC_FREE(fsp->update_write_time_event);
@@ -853,93 +941,51 @@ bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
******************************************************************/
NTSTATUS set_create_timespec_ea(connection_struct *conn,
- struct files_struct *fsp,
- const struct smb_filename *smb_fname,
+ const struct smb_filename *psmb_fname,
struct timespec create_time)
{
+ NTSTATUS status;
+ struct smb_filename *smb_fname = NULL;
+ uint32_t dosmode;
int ret;
- char buf[8];
- if (!lp_store_create_time(SNUM(conn))) {
+ if (!lp_store_dos_attributes(SNUM(conn))) {
return NT_STATUS_OK;
}
- put_long_date_timespec(conn->ts_res, buf, create_time);
- if (fsp && fsp->fh->fd != -1) {
- ret = SMB_VFS_FSETXATTR(fsp,
- SAMBA_XATTR_DOSTIMESTAMPS,
- buf,
- sizeof(buf),
- 0);
- } else {
- ret = SMB_VFS_SETXATTR(conn,
- smb_fname->base_name,
- SAMBA_XATTR_DOSTIMESTAMPS,
- buf,
- sizeof(buf),
- 0);
+ status = create_synthetic_smb_fname(talloc_tos(),
+ psmb_fname->base_name,
+ NULL, &psmb_fname->st,
+ &smb_fname);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
+ dosmode = dos_mode(conn, smb_fname);
+
+ smb_fname->st.st_ex_btime = create_time;
+
+ ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
if (ret == -1) {
map_nt_error_from_unix(errno);
}
+
DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
smb_fname_str_dbg(smb_fname)));
- return NT_STATUS_OK;
-}
-/******************************************************************
- Returns an EA create timespec, or a zero timespec if fail.
-******************************************************************/
-
-static struct timespec get_create_timespec_ea(connection_struct *conn,
- struct files_struct *fsp,
- const struct smb_filename *smb_fname)
-{
- ssize_t ret;
- char buf[8];
- struct timespec ts;
-
- ZERO_STRUCT(ts);
-
- if (!lp_store_create_time(SNUM(conn))) {
- return ts;
- }
-
- if (fsp && fsp->fh->fd != -1) {
- ret = SMB_VFS_FGETXATTR(fsp,
- SAMBA_XATTR_DOSTIMESTAMPS,
- buf,
- sizeof(buf));
- } else {
- ret = SMB_VFS_GETXATTR(conn,
- smb_fname->base_name,
- SAMBA_XATTR_DOSTIMESTAMPS,
- buf,
- sizeof(buf));
- }
- if (ret == sizeof(buf)) {
- return interpret_long_date(buf);
- } else {
- return ts;
- }
+ return NT_STATUS_OK;
}
/******************************************************************
- Return a create time - looks at EA.
+ Return a create time.
******************************************************************/
struct timespec get_create_timespec(connection_struct *conn,
struct files_struct *fsp,
const struct smb_filename *smb_fname)
{
- struct timespec ts = get_create_timespec_ea(conn, fsp, smb_fname);
-
- if (!null_timespec(ts)) {
- return ts;
- } else {
- return smb_fname->st.st_ex_btime;
- }
+ return smb_fname->st.st_ex_btime;
}
/******************************************************************