Commit 56831a1a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [CIFS] list entry can not return null
  turn cifs_setattr into a multiplexor that calls the correct function
  move file time and dos attribute setting logic into new function
  spin off cifs_setattr with unix extensions to its own function
  [CIFS] Code cleanup in old sessionsetup code
  [CIFS] cifs_mkdir and cifs_create should respect the setgid bit on parent dir
  Rename CIFSSMBSetFileTimes to CIFSSMBSetFileInfo and add PID arg
  change CIFSSMBSetTimes to CIFSSMBSetPathInfo
  [CIFS] fix trailing whitespace
  bundle up Unix SET_PATH_INFO args into a struct and change name
  Fix missing braces in cifs_revalidate()
  remove locking around tcpSesAllocCount atomic variable
  [CIFS] properly account for new user= field in SPNEGO upcall string allocation
  [CIFS] remove level of indentation from decode_negTokenInit
  [CIFS] cifs send2 not retrying enough in some cases on full socket
  [CIFS] oid should also be checked against class in cifs asn
parents 6724cce8 ad8b15f0
Version 1.54
------------
Fix premature write failure on congested networks (we would give up
on EAGAIN from the socket too quickly on large writes).
Cifs_mkdir and cifs_create now respect the setgid bit on parent dir.
Fix endian problems in acl (mode from/to cifs acl) on bigendian
architectures.
Version 1.53 Version 1.53
------------ ------------
DFS support added (Microsoft Distributed File System client support needed DFS support added (Microsoft Distributed File System client support needed
......
...@@ -483,6 +483,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, ...@@ -483,6 +483,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
asn1_open(&ctx, security_blob, length); asn1_open(&ctx, security_blob, length);
/* GSSAPI header */
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, ("Error decoding negTokenInit header")); cFYI(1, ("Error decoding negTokenInit header"));
return 0; return 0;
...@@ -490,153 +491,142 @@ decode_negTokenInit(unsigned char *security_blob, int length, ...@@ -490,153 +491,142 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|| (tag != ASN1_EOC)) { || (tag != ASN1_EOC)) {
cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag)); cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag));
return 0; return 0;
} else { }
/* remember to free obj->oid */
rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
if (rc) {
if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
if (rc) {
rc = compare_oid(oid, oidlen,
SPNEGO_OID,
SPNEGO_OID_LEN);
kfree(oid);
}
} else
rc = 0;
}
if (!rc) { /* Check for SPNEGO OID -- remember to free obj->oid */
cFYI(1, ("Error decoding negTokenInit header")); rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
return 0; if (rc) {
} if ((tag == ASN1_OJI) && (con == ASN1_PRI) &&
(cls == ASN1_UNI)) {
rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
if (rc) {
rc = compare_oid(oid, oidlen, SPNEGO_OID,
SPNEGO_OID_LEN);
kfree(oid);
}
} else
rc = 0;
}
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { /* SPNEGO OID not present or garbled -- bail out */
cFYI(1, ("Error decoding negTokenInit")); if (!rc) {
return 0; cFYI(1, ("Error decoding negTokenInit header"));
} else if ((cls != ASN1_CTX) || (con != ASN1_CON) return 0;
|| (tag != ASN1_EOC)) { }
cFYI(1,
("cls = %d con = %d tag = %d end = %p (%d) exit 0",
cls, con, tag, end, *end));
return 0;
}
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, ("Error decoding negTokenInit")); cFYI(1, ("Error decoding negTokenInit"));
return 0; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) { || (tag != ASN1_EOC)) {
cFYI(1, cFYI(1,
("cls = %d con = %d tag = %d end = %p (%d) exit 1", ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
return 0; return 0;
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, ("Error decoding 2nd part of negTokenInit")); cFYI(1, ("Error decoding negTokenInit"));
return 0; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON) } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_EOC)) { || (tag != ASN1_SEQ)) {
cFYI(1, cFYI(1,
("cls = %d con = %d tag = %d end = %p (%d) exit 0", ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
return 0; return 0;
} }
if (asn1_header_decode if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
(&ctx, &sequence_end, &cls, &con, &tag) == 0) { cFYI(1, ("Error decoding 2nd part of negTokenInit"));
cFYI(1, ("Error decoding 2nd part of negTokenInit")); return 0;
return 0; } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_EOC)) {
|| (tag != ASN1_SEQ)) { cFYI(1,
cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
("cls = %d con = %d tag = %d end = %p (%d) exit 1", cls, con, tag, end, *end));
cls, con, tag, end, *end)); return 0;
return 0; }
}
while (!asn1_eoc_decode(&ctx, sequence_end)) { if (asn1_header_decode
rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
if (!rc) { cFYI(1, ("Error decoding 2nd part of negTokenInit"));
cFYI(1, return 0;
("Error decoding negTokenInit hdr exit2")); } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
return 0; || (tag != ASN1_SEQ)) {
} cFYI(1,
if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) { cls, con, tag, end, *end));
return 0;
cFYI(1, }
("OID len = %d oid = 0x%lx 0x%lx "
"0x%lx 0x%lx",
oidlen, *oid, *(oid + 1),
*(oid + 2), *(oid + 3)));
if (compare_oid(oid, oidlen,
MSKRB5_OID,
MSKRB5_OID_LEN))
use_kerberos = true;
else if (compare_oid(oid, oidlen,
KRB5_OID,
KRB5_OID_LEN))
use_kerberos = true;
else if (compare_oid(oid, oidlen,
NTLMSSP_OID,
NTLMSSP_OID_LEN))
use_ntlmssp = true;
kfree(oid);
}
} else {
cFYI(1, ("Should be an oid what is going on?"));
}
}
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { while (!asn1_eoc_decode(&ctx, sequence_end)) {
cFYI(1, rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
("Error decoding last part negTokenInit exit3")); if (!rc) {
return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
/* tag = 3 indicating mechListMIC */
cFYI(1, cFYI(1,
("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", ("Error decoding negTokenInit hdr exit2"));
cls, con, tag, end, *end));
return 0; return 0;
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
cFYI(1, if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
("Error decoding last part negTokenInit exit5"));
return 0; cFYI(1, ("OID len = %d oid = 0x%lx 0x%lx "
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) "0x%lx 0x%lx", oidlen, *oid,
|| (tag != ASN1_SEQ)) { *(oid + 1), *(oid + 2), *(oid + 3)));
cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end)); if (compare_oid(oid, oidlen, MSKRB5_OID,
MSKRB5_OID_LEN))
use_kerberos = true;
else if (compare_oid(oid, oidlen, KRB5_OID,
KRB5_OID_LEN))
use_kerberos = true;
else if (compare_oid(oid, oidlen, NTLMSSP_OID,
NTLMSSP_OID_LEN))
use_ntlmssp = true;
kfree(oid);
}
} else {
cFYI(1, ("Should be an oid what is going on?"));
} }
}
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1, ("Error decoding last part negTokenInit exit3"));
("Error decoding last part negTokenInit exit 7")); return 0;
return 0; } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */
cFYI(1, cFYI(1, ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
("Exit 8 cls = %d con = %d tag = %d end = %p (%d)", cls, con, tag, end, *end));
cls, con, tag, end, *end)); return 0;
return 0; }
} if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { cFYI(1, ("Error decoding last part negTokenInit exit5"));
cFYI(1, return 0;
("Error decoding last part negTokenInit exit9")); } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
return 0; || (tag != ASN1_SEQ)) {
} else if ((cls != ASN1_UNI) || (con != ASN1_PRI) cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",
|| (tag != ASN1_GENSTR)) { cls, con, tag, end, *end));
cFYI(1, }
("Exit10 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end)); if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
return 0; cFYI(1, ("Error decoding last part negTokenInit exit 7"));
} return 0;
cFYI(1, ("Need to call asn1_octets_decode() function for %s", } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
ctx.pointer)); /* is this UTF-8 or ASCII? */ cFYI(1, ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end));
return 0;
}
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, ("Error decoding last part negTokenInit exit9"));
return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
|| (tag != ASN1_GENSTR)) {
cFYI(1, ("Exit10 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end));
return 0;
} }
cFYI(1, ("Need to call asn1_octets_decode() function for %s",
ctx.pointer)); /* is this UTF-8 or ASCII? */
if (use_kerberos) if (use_kerberos)
*secType = Kerberos; *secType = Kerberos;
......
...@@ -79,27 +79,25 @@ void cifs_dump_mids(struct TCP_Server_Info *server) ...@@ -79,27 +79,25 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) { list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead); mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if (mid_entry) { cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", mid_entry->midState,
mid_entry->midState, (int)mid_entry->command,
(int)mid_entry->command, mid_entry->pid,
mid_entry->pid, mid_entry->tsk,
mid_entry->tsk, mid_entry->mid));
mid_entry->mid));
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld", cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld",
mid_entry->largeBuf, mid_entry->largeBuf,
mid_entry->resp_buf, mid_entry->resp_buf,
mid_entry->when_received, mid_entry->when_received,
jiffies)); jiffies));
#endif /* STATS2 */ #endif /* STATS2 */
cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp, cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
mid_entry->multiEnd)); mid_entry->multiEnd));
if (mid_entry->resp_buf) { if (mid_entry->resp_buf) {
cifs_dump_detail(mid_entry->resp_buf); cifs_dump_detail(mid_entry->resp_buf);
cifs_dump_mem("existing buf: ", cifs_dump_mem("existing buf: ",
mid_entry->resp_buf, 62); mid_entry->resp_buf, 62);
}
} }
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -163,16 +161,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -163,16 +161,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
mid_entry = list_entry(tmp1, struct mid_entry = list_entry(tmp1, struct
mid_q_entry, mid_q_entry,
qhead); qhead);
if (mid_entry) { seq_printf(m, "State: %d com: %d pid:"
seq_printf(m, " %d tsk: %p mid %d\n",
"State: %d com: %d pid:" mid_entry->midState,
" %d tsk: %p mid %d\n", (int)mid_entry->command,
mid_entry->midState, mid_entry->pid,
(int)mid_entry->command, mid_entry->tsk,
mid_entry->pid, mid_entry->mid);
mid_entry->tsk,
mid_entry->mid);
}
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
} }
......
...@@ -66,8 +66,8 @@ struct key_type cifs_spnego_key_type = { ...@@ -66,8 +66,8 @@ struct key_type cifs_spnego_key_type = {
.describe = user_describe, .describe = user_describe,
}; };
#define MAX_VER_STR_LEN 9 /* length of longest version string e.g. #define MAX_VER_STR_LEN 8 /* length of longest version string e.g.
strlen(";ver=0xFF") */ strlen("ver=0xFF") */
#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
in future could have strlen(";sec=ntlmsspi") */ in future could have strlen(";sec=ntlmsspi") */
#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ #define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
...@@ -81,11 +81,15 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) ...@@ -81,11 +81,15 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
struct key *spnego_key; struct key *spnego_key;
const char *hostname = server->hostname; const char *hostname = server->hostname;
/* BB: come up with better scheme for determining length */ /* length of fields (with semicolons): ver=0xyz ip4=ipaddress
/* length of fields (with semicolons): ver=0xyz ipv4= ipaddress host= host=hostname sec=mechanism uid=0xFF user=username */
hostname sec=mechanism uid=0x uid */ desc_len = MAX_VER_STR_LEN +
desc_len = MAX_VER_STR_LEN + 5 + MAX_IPV6_ADDR_LEN + 1 + 6 + 6 /* len of "host=" */ + strlen(hostname) +
strlen(hostname) + MAX_MECH_STR_LEN + 8 + (sizeof(uid_t) * 2); 5 /* len of ";ipv4=" */ + MAX_IPV6_ADDR_LEN +
MAX_MECH_STR_LEN +
7 /* len of ";uid=0x" */ + (sizeof(uid_t) * 2) +
6 /* len of ";user=" */ + strlen(sesInfo->userName) + 1;
spnego_key = ERR_PTR(-ENOMEM); spnego_key = ERR_PTR(-ENOMEM);
description = kzalloc(desc_len, GFP_KERNEL); description = kzalloc(desc_len, GFP_KERNEL);
if (description == NULL) if (description == NULL)
......
...@@ -930,36 +930,34 @@ static int cifs_oplock_thread(void *dummyarg) ...@@ -930,36 +930,34 @@ static int cifs_oplock_thread(void *dummyarg)
schedule_timeout(39*HZ); schedule_timeout(39*HZ);
} else { } else {
oplock_item = list_entry(GlobalOplock_Q.next, oplock_item = list_entry(GlobalOplock_Q.next,
struct oplock_q_entry, qhead); struct oplock_q_entry, qhead);
if (oplock_item) { cFYI(1, ("found oplock item to write out"));
cFYI(1, ("found oplock item to write out")); pTcon = oplock_item->tcon;
pTcon = oplock_item->tcon; inode = oplock_item->pinode;
inode = oplock_item->pinode; netfid = oplock_item->netfid;
netfid = oplock_item->netfid; spin_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock); DeleteOplockQEntry(oplock_item);
DeleteOplockQEntry(oplock_item); /* can not grab inode sem here since it would
/* can not grab inode sem here since it would
deadlock when oplock received on delete deadlock when oplock received on delete
since vfs_unlink holds the i_mutex across since vfs_unlink holds the i_mutex across
the call */ the call */
/* mutex_lock(&inode->i_mutex);*/ /* mutex_lock(&inode->i_mutex);*/
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
rc = rc = filemap_fdatawrite(inode->i_mapping);
filemap_fdatawrite(inode->i_mapping); if (CIFS_I(inode)->clientCanCacheRead == 0) {
if (CIFS_I(inode)->clientCanCacheRead waitrc = filemap_fdatawait(
== 0) { inode->i_mapping);
waitrc = filemap_fdatawait(inode->i_mapping); invalidate_remote_inode(inode);
invalidate_remote_inode(inode); }
} if (rc == 0)
if (rc == 0) rc = waitrc;
rc = waitrc; } else
} else rc = 0;
rc = 0; /* mutex_unlock(&inode->i_mutex);*/
/* mutex_unlock(&inode->i_mutex);*/ if (rc)
if (rc) CIFS_I(inode)->write_behind_rc = rc;
CIFS_I(inode)->write_behind_rc = rc; cFYI(1, ("Oplock flush inode %p rc %d",
cFYI(1, ("Oplock flush inode %p rc %d", inode, rc));
inode, rc));
/* releasing stale oplock after recent reconnect /* releasing stale oplock after recent reconnect
of smb session using a now incorrect file of smb session using a now incorrect file
...@@ -967,15 +965,13 @@ static int cifs_oplock_thread(void *dummyarg) ...@@ -967,15 +965,13 @@ static int cifs_oplock_thread(void *dummyarg)
not bother sending an oplock release if session not bother sending an oplock release if session
to server still is disconnected since oplock to server still is disconnected since oplock
already released by the server in that case */ already released by the server in that case */
if (pTcon->tidStatus != CifsNeedReconnect) { if (pTcon->tidStatus != CifsNeedReconnect) {
rc = CIFSSMBLock(0, pTcon, netfid, rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0, 0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE, 0, LOCKING_ANDX_OPLOCK_RELEASE,
false /* wait flag */); false /* wait flag */);
cFYI(1, ("Oplock release rc = %d", rc)); cFYI(1, ("Oplock release rc = %d", rc));
} }
} else
spin_unlock(&GlobalMid_Lock);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1); /* yield in case q were corrupt */ schedule_timeout(1); /* yield in case q were corrupt */
} }
...@@ -1001,8 +997,7 @@ static int cifs_dnotify_thread(void *dummyarg) ...@@ -1001,8 +997,7 @@ static int cifs_dnotify_thread(void *dummyarg)
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList); cifsSessionList);
if (ses && ses->server && if (ses->server && atomic_read(&ses->server->inFlight))
atomic_read(&ses->server->inFlight))
wake_up_all(&ses->server->response_q); wake_up_all(&ses->server->response_q);
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
......
...@@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ...@@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */ #endif /* EXPERIMENTAL */
#define CIFS_VERSION "1.53" #define CIFS_VERSION "1.54"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -262,7 +262,7 @@ ...@@ -262,7 +262,7 @@
*/ */
#define CIFS_NO_HANDLE 0xFFFF #define CIFS_NO_HANDLE 0xFFFF
#define NO_CHANGE_64 cpu_to_le64(0xFFFFFFFFFFFFFFFFULL) #define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL
#define NO_CHANGE_32 0xFFFFFFFFUL #define NO_CHANGE_32 0xFFFFFFFFUL
/* IPC$ in ASCII */ /* IPC$ in ASCII */
......
...@@ -172,12 +172,13 @@ extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon); ...@@ -172,12 +172,13 @@ extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon);
extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
struct kstatfs *FSData); struct kstatfs *FSData);
extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const FILE_BASIC_INFO *data, const char *fileName, const FILE_BASIC_INFO *data,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
const FILE_BASIC_INFO *data, __u16 fid); const FILE_BASIC_INFO *data, __u16 fid,
__u32 pid_of_opener);
#if 0 #if 0
extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
char *fileName, __u16 dos_attributes, char *fileName, __u16 dos_attributes,
...@@ -191,9 +192,20 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, ...@@ -191,9 +192,20 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
__u64 size, __u16 fileHandle, __u32 opener_pid, __u64 size, __u16 fileHandle, __u32 opener_pid,
bool AllocSizeFlag); bool AllocSizeFlag);
extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
char *full_path, __u64 mode, __u64 uid, struct cifs_unix_set_info_args {
__u64 gid, dev_t dev, __u64 ctime;
__u64 atime;
__u64 mtime;
__u64 mode;
__u64 uid;
__u64 gid;
dev_t device;
};
extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon,
char *fileName,
const struct cifs_unix_set_info_args *args,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
......
...@@ -128,8 +128,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon) ...@@ -128,8 +128,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
open_file = list_entry(tmp, struct cifsFileInfo, tlist); open_file = list_entry(tmp, struct cifsFileInfo, tlist);
if (open_file) open_file->invalidHandle = true;
open_file->invalidHandle = true;
} }
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
/* BB Add call to invalidate_inodes(sb) for all superblocks mounted /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
...@@ -4816,8 +4815,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, ...@@ -4816,8 +4815,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
time and resort to the original setpathinfo level which takes the ancient time and resort to the original setpathinfo level which takes the ancient
DOS time format with 2 second granularity */ DOS time format with 2 second granularity */
int int
CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
const FILE_BASIC_INFO *data, __u16 fid) const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
{ {
struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_req *pSMB = NULL;
char *data_offset; char *data_offset;
...@@ -4830,11 +4829,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, ...@@ -4830,11 +4829,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
if (rc) if (rc)
return rc; return rc;
/* At this point there is no need to override the current pid pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
with the pid of the opener, but that could change if we someday pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
use an existing handle (rather than opening one on the fly) */
/* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
params = 6; params = 6;
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
...@@ -4882,9 +4878,9 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, ...@@ -4882,9 +4878,9 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
int int
CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
const FILE_BASIC_INFO *data, const char *fileName, const FILE_BASIC_INFO *data,
const struct nls_table *nls_codepage, int remap) const struct nls_table *nls_codepage, int remap)
{ {
TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL;
...@@ -5013,10 +5009,9 @@ CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName, ...@@ -5013,10 +5009,9 @@ CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
#endif /* temporarily unneeded SetAttr legacy function */ #endif /* temporarily unneeded SetAttr legacy function */
int int
CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
char *fileName, __u64 mode, __u64 uid, __u64 gid, const struct cifs_unix_set_info_args *args,
dev_t device, const struct nls_table *nls_codepage, const struct nls_table *nls_codepage, int remap)
int remap)
{ {
TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL;
...@@ -5025,6 +5020,7 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, ...@@ -5025,6 +5020,7 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
int bytes_returned = 0; int bytes_returned = 0;
FILE_UNIX_BASIC_INFO *data_offset; FILE_UNIX_BASIC_INFO *data_offset;
__u16 params, param_offset, offset, count, byte_count; __u16 params, param_offset, offset, count, byte_count;
__u64 mode = args->mode;
cFYI(1, ("In SetUID/GID/Mode")); cFYI(1, ("In SetUID/GID/Mode"));
setPermsRetry: setPermsRetry:
...@@ -5080,16 +5076,16 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, ...@@ -5080,16 +5076,16 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
set file size and do not want to truncate file size to zero set file size and do not want to truncate file size to zero
accidently as happened on one Samba server beta by putting accidently as happened on one Samba server beta by putting
zero instead of -1 here */ zero instead of -1 here */
data_offset->EndOfFile = NO_CHANGE_64; data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
data_offset->NumOfBytes = NO_CHANGE_64; data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
data_offset->LastStatusChange = NO_CHANGE_64; data_offset->LastStatusChange = cpu_to_le64(args->ctime);
data_offset->LastAccessTime = NO_CHANGE_64; data_offset->LastAccessTime = cpu_to_le64(args->atime);
data_offset->LastModificationTime = NO_CHANGE_64; data_offset->LastModificationTime = cpu_to_le64(args->mtime);
data_offset->Uid = cpu_to_le64(uid); data_offset->Uid = cpu_to_le64(args->uid);
data_offset->Gid = cpu_to_le64(gid); data_offset->Gid = cpu_to_le64(args->gid);
/* better to leave device as zero when it is */ /* better to leave device as zero when it is */
data_offset->DevMajor = cpu_to_le64(MAJOR(device)); data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
data_offset->DevMinor = cpu_to_le64(MINOR(device)); data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
data_offset->Permissions = cpu_to_le64(mode); data_offset->Permissions = cpu_to_le64(mode);
if (S_ISREG(mode)) if (S_ISREG(mode))
......
...@@ -151,7 +151,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -151,7 +151,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
} }
list_for_each(tmp, &GlobalTreeConnectionList) { list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) if ((tcon->ses) && (tcon->ses->server == server))
tcon->tidStatus = CifsNeedReconnect; tcon->tidStatus = CifsNeedReconnect;
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
...@@ -173,14 +173,12 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -173,14 +173,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
mid_entry = list_entry(tmp, struct mid_entry = list_entry(tmp, struct
mid_q_entry, mid_q_entry,
qhead); qhead);
if (mid_entry) { if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
/* Mark other intransit requests as needing /* Mark other intransit requests as needing
retry so we do not immediately mark the retry so we do not immediately mark the
session bad again (ie after we reconnect session bad again (ie after we reconnect
below) as they timeout too */ below) as they timeout too */
mid_entry->midState = MID_RETRY_NEEDED; mid_entry->midState = MID_RETRY_NEEDED;
}
} }
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -351,11 +349,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -351,11 +349,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
current->flags |= PF_MEMALLOC; current->flags |= PF_MEMALLOC;
cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current))); cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
write_lock(&GlobalSMBSeslock);
atomic_inc(&tcpSesAllocCount); length = atomic_inc_return(&tcpSesAllocCount);
length = tcpSesAllocCount.counter; if (length > 1)
write_unlock(&GlobalSMBSeslock);
if (length > 1)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv, mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
GFP_KERNEL); GFP_KERNEL);
...@@ -745,14 +741,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -745,14 +741,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
coming home not much else we can do but free the memory */ coming home not much else we can do but free the memory */
} }
write_lock(&GlobalSMBSeslock);
atomic_dec(&tcpSesAllocCount);
length = tcpSesAllocCount.counter;
/* last chance to mark ses pointers invalid /* last chance to mark ses pointers invalid
if there are any pointing to this (e.g if there are any pointing to this (e.g
if a crazy root user tried to kill cifsd if a crazy root user tried to kill cifsd
kernel thread explicitly this might happen) */ kernel thread explicitly this might happen) */
write_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList); cifsSessionList);
...@@ -763,6 +756,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -763,6 +756,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
kfree(server->hostname); kfree(server->hostname);
kfree(server); kfree(server);
length = atomic_dec_return(&tcpSesAllocCount);
if (length > 0) if (length > 0)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv, mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
GFP_KERNEL); GFP_KERNEL);
...@@ -3623,97 +3618,91 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3623,97 +3618,91 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
} }
first_time = 1; first_time = 1;
} }
if (!rc) {
pSesInfo->flags = 0; if (rc)
pSesInfo->capabilities = pSesInfo->server->capabilities; goto ss_err_exit;
if (linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX); pSesInfo->flags = 0;
pSesInfo->capabilities = pSesInfo->server->capabilities;
if (linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX);
/* pSesInfo->sequence_number = 0;*/ /* pSesInfo->sequence_number = 0;*/
cFYI(1, cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", pSesInfo->server->secMode,
pSesInfo->server->secMode, pSesInfo->server->capabilities,
pSesInfo->server->capabilities, pSesInfo->server->timeAdj));
pSesInfo->server->timeAdj)); if (experimEnabled < 2)
if (experimEnabled < 2) rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
rc = CIFS_SessSetup(xid, pSesInfo, else if (extended_security
first_time, nls_info); && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
else if (extended_security && (pSesInfo->server->secType == NTLMSSP)) {
&& (pSesInfo->capabilities rc = -EOPNOTSUPP;
& CAP_EXTENDED_SECURITY) } else if (extended_security
&& (pSesInfo->server->secType == NTLMSSP)) { && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
rc = -EOPNOTSUPP; && (pSesInfo->server->secType == RawNTLMSSP)) {
} else if (extended_security cFYI(1, ("NTLMSSP sesssetup"));
&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
&& (pSesInfo->server->secType == RawNTLMSSP)) { nls_info);
cFYI(1, ("NTLMSSP sesssetup")); if (!rc) {
rc = CIFSNTLMSSPNegotiateSessSetup(xid, if (ntlmv2_flag) {
pSesInfo, char *v2_response;
&ntlmv2_flag, cFYI(1, ("more secure NTLM ver2 hash"));
nls_info); if (CalcNTLMv2_partial_mac_key(pSesInfo,
if (!rc) { nls_info)) {
if (ntlmv2_flag) { rc = -ENOMEM;
char *v2_response; goto ss_err_exit;
cFYI(1, ("more secure NTLM ver2 hash")); } else
if (CalcNTLMv2_partial_mac_key(pSesInfo, v2_response = kmalloc(16 + 64 /* blob*/,
nls_info)) { GFP_KERNEL);
rc = -ENOMEM; if (v2_response) {
goto ss_err_exit; CalcNTLMv2_response(pSesInfo,
} else v2_response);
v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); /* if (first_time)
if (v2_response) { cifs_calculate_ntlmv2_mac_key */
CalcNTLMv2_response(pSesInfo, kfree(v2_response);
v2_response);
/* if (first_time)
cifs_calculate_ntlmv2_mac_key(
pSesInfo->server->mac_signing_key,
response, ntlm_session_key,*/
kfree(v2_response);
/* BB Put dummy sig in SessSetup PDU? */ /* BB Put dummy sig in SessSetup PDU? */
} else {
rc = -ENOMEM;
goto ss_err_exit;
}
} else { } else {
SMBNTencrypt(pSesInfo->password, rc = -ENOMEM;
pSesInfo->server->cryptKey, goto ss_err_exit;
ntlm_session_key);
if (first_time)
cifs_calculate_mac_key(
&pSesInfo->server->mac_signing_key,
ntlm_session_key,
pSesInfo->password);
} }
} else {
SMBNTencrypt(pSesInfo->password,
pSesInfo->server->cryptKey,
ntlm_session_key);
if (first_time)
cifs_calculate_mac_key(
&pSesInfo->server->mac_signing_key,
ntlm_session_key,
pSesInfo->password);
}
/* for better security the weaker lanman hash not sent /* for better security the weaker lanman hash not sent
in AuthSessSetup so we no longer calculate it */ in AuthSessSetup so we no longer calculate it */
rc = CIFSNTLMSSPAuthSessSetup(xid, rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
pSesInfo, ntlm_session_key,
ntlm_session_key, ntlmv2_flag,
ntlmv2_flag, nls_info);
nls_info); }
} } else { /* old style NTLM 0.12 session setup */
} else { /* old style NTLM 0.12 session setup */ SMBNTencrypt(pSesInfo->password, pSesInfo->server->cryptKey,
SMBNTencrypt(pSesInfo->password, ntlm_session_key);
pSesInfo->server->cryptKey,
ntlm_session_key);
if (first_time) if (first_time)
cifs_calculate_mac_key( cifs_calculate_mac_key(
&pSesInfo->server->mac_signing_key, &pSesInfo->server->mac_signing_key,
ntlm_session_key, pSesInfo->password); ntlm_session_key, pSesInfo->password);
rc = CIFSSessSetup(xid, pSesInfo, rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
ntlm_session_key, nls_info); }
} if (rc) {
if (rc) { cERROR(1, ("Send error in SessSetup = %d", rc));
cERROR(1, ("Send error in SessSetup = %d", rc)); } else {
} else { cFYI(1, ("CIFS Session Established successfully"));
cFYI(1, ("CIFS Session Established successfully"));
pSesInfo->status = CifsGood; pSesInfo->status = CifsGood;
}
} }
ss_err_exit: ss_err_exit:
return rc; return rc;
} }
......
...@@ -226,23 +226,28 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -226,23 +226,28 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
/* If Open reported that we actually created a file /* If Open reported that we actually created a file
then we now have to set the mode if possible */ then we now have to set the mode if possible */
if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
struct cifs_unix_set_info_args args = {
.mode = mode,
.ctime = NO_CHANGE_64,
.atime = NO_CHANGE_64,
.mtime = NO_CHANGE_64,
.device = 0,
};
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, args.uid = (__u64) current->fsuid;
(__u64)current->fsuid, if (inode->i_mode & S_ISGID)
(__u64)current->fsgid, args.gid = (__u64) inode->i_gid;
0 /* dev */, else
cifs_sb->local_nls, args.gid = (__u64) current->fsgid;
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else { } else {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, args.uid = NO_CHANGE_64;
(__u64)-1, args.gid = NO_CHANGE_64;
(__u64)-1,
0 /* dev */,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else { } else {
/* BB implement mode setting via Windows security /* BB implement mode setting via Windows security
descriptors e.g. */ descriptors e.g. */
...@@ -267,7 +272,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -267,7 +272,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
(cifs_sb->mnt_cifs_flags & (cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_SET_UID)) { CIFS_MOUNT_SET_UID)) {
newinode->i_uid = current->fsuid; newinode->i_uid = current->fsuid;
newinode->i_gid = current->fsgid; if (inode->i_mode & S_ISGID)
newinode->i_gid =
inode->i_gid;
else
newinode->i_gid =
current->fsgid;
} }
} }
} }
...@@ -357,21 +367,24 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, ...@@ -357,21 +367,24 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
if (full_path == NULL) if (full_path == NULL)
rc = -ENOMEM; rc = -ENOMEM;
else if (pTcon->unix_ext) { else if (pTcon->unix_ext) {
mode &= ~current->fs->umask; struct cifs_unix_set_info_args args = {
.mode = mode & ~current->fs->umask,
.ctime = NO_CHANGE_64,
.atime = NO_CHANGE_64,
.mtime = NO_CHANGE_64,
.device = device_number,
};
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, args.uid = (__u64) current->fsuid;
mode, (__u64)current->fsuid, args.gid = (__u64) current->fsgid;
(__u64)current->fsgid,
device_number, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else { } else {
rc = CIFSSMBUnixSetPerms(xid, pTcon, args.uid = NO_CHANGE_64;
full_path, mode, (__u64)-1, (__u64)-1, args.gid = NO_CHANGE_64;
device_number, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
&args, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) { if (!rc) {
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
......
...@@ -310,18 +310,19 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -310,18 +310,19 @@ int cifs_open(struct inode *inode, struct file *file)
/* time to set mode which we can not set earlier due to /* time to set mode which we can not set earlier due to
problems creating new read-only files */ problems creating new read-only files */
if (pTcon->unix_ext) { if (pTcon->unix_ext) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, struct cifs_unix_set_info_args args = {
inode->i_mode, .mode = inode->i_mode,
(__u64)-1, (__u64)-1, 0 /* dev */, .uid = NO_CHANGE_64,
.gid = NO_CHANGE_64,
.ctime = NO_CHANGE_64,
.atime = NO_CHANGE_64,
.mtime = NO_CHANGE_64,
.device = 0,
};
CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
/* BB implement via Windows security descriptors eg
CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
-1, -1, local_nls);
in the meantime could set r/o dos attribute when
perms are eg: mode & 0222 == 0 */
} }
} }
......
...@@ -737,7 +737,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -737,7 +737,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
/* ATTRS set to normal clears r/o bit */ /* ATTRS set to normal clears r/o bit */
pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
if (!(pTcon->ses->flags & CIFS_SES_NT4)) if (!(pTcon->ses->flags & CIFS_SES_NT4))
rc = CIFSSMBSetTimes(xid, pTcon, full_path, rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
pinfo_buf, pinfo_buf,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
...@@ -767,9 +767,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -767,9 +767,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == 0) { if (rc == 0) {
rc = CIFSSMBSetFileTimes(xid, pTcon, rc = CIFSSMBSetFileInfo(xid, pTcon,
pinfo_buf, pinfo_buf,
netfid); netfid,
current->tgid);
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, pTcon, netfid);
} }
} }
...@@ -984,32 +985,41 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -984,32 +985,41 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
* failed to get it from the server or was set bogus */ * failed to get it from the server or was set bogus */
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
direntry->d_inode->i_nlink = 2; direntry->d_inode->i_nlink = 2;
mode &= ~current->fs->umask; mode &= ~current->fs->umask;
/* must turn on setgid bit if parent dir has it */
if (inode->i_mode & S_ISGID)
mode |= S_ISGID;
if (pTcon->unix_ext) { if (pTcon->unix_ext) {
struct cifs_unix_set_info_args args = {
.mode = mode,
.ctime = NO_CHANGE_64,
.atime = NO_CHANGE_64,
.mtime = NO_CHANGE_64,
.device = 0,
};
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, args.uid = (__u64)current->fsuid;
mode, if (inode->i_mode & S_ISGID)
(__u64)current->fsuid, args.gid = (__u64)inode->i_gid;
(__u64)current->fsgid, else
0 /* dev_t */, args.gid = (__u64)current->fsgid;
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else { } else {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, args.uid = NO_CHANGE_64;
mode, (__u64)-1, args.gid = NO_CHANGE_64;
(__u64)-1, 0 /* dev_t */,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else { } else {
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
(mode & S_IWUGO) == 0) { (mode & S_IWUGO) == 0) {
FILE_BASIC_INFO pInfo; FILE_BASIC_INFO pInfo;
memset(&pInfo, 0, sizeof(pInfo)); memset(&pInfo, 0, sizeof(pInfo));
pInfo.Attributes = cpu_to_le32(ATTR_READONLY); pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
CIFSSMBSetTimes(xid, pTcon, full_path, CIFSSMBSetPathInfo(xid, pTcon, full_path,
&pInfo, cifs_sb->local_nls, &pInfo, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
...@@ -1024,8 +1034,12 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -1024,8 +1034,12 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
CIFS_MOUNT_SET_UID) { CIFS_MOUNT_SET_UID) {
direntry->d_inode->i_uid = direntry->d_inode->i_uid =
current->fsuid; current->fsuid;
direntry->d_inode->i_gid = if (inode->i_mode & S_ISGID)
current->fsgid; direntry->d_inode->i_gid =
inode->i_gid;
else
direntry->d_inode->i_gid =
current->fsgid;
} }
} }
} }
...@@ -1310,10 +1324,11 @@ int cifs_revalidate(struct dentry *direntry) ...@@ -1310,10 +1324,11 @@ int cifs_revalidate(struct dentry *direntry)
/* if (S_ISDIR(direntry->d_inode->i_mode)) /* if (S_ISDIR(direntry->d_inode->i_mode))
shrink_dcache_parent(direntry); */ shrink_dcache_parent(direntry); */
if (S_ISREG(direntry->d_inode->i_mode)) { if (S_ISREG(direntry->d_inode->i_mode)) {
if (direntry->d_inode->i_mapping) if (direntry->d_inode->i_mapping) {
wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
if (wbrc) if (wbrc)
CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
}
/* may eventually have to do this for open files too */ /* may eventually have to do this for open files too */
if (list_empty(&(cifsInode->openFileList))) { if (list_empty(&(cifsInode->openFileList))) {
/* changed on server - flush read ahead pages */ /* changed on server - flush read ahead pages */
...@@ -1489,30 +1504,228 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, ...@@ -1489,30 +1504,228 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
return rc; return rc;
} }
int cifs_setattr(struct dentry *direntry, struct iattr *attrs) static int
cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
char *full_path, __u32 dosattr)
{
int rc;
int oplock = 0;
__u16 netfid;
__u32 netpid;
bool set_time = false;
struct cifsFileInfo *open_file;
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *pTcon = cifs_sb->tcon;
FILE_BASIC_INFO info_buf;
if (attrs->ia_valid & ATTR_ATIME) {
set_time = true;
info_buf.LastAccessTime =
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
} else
info_buf.LastAccessTime = 0;
if (attrs->ia_valid & ATTR_MTIME) {
set_time = true;
info_buf.LastWriteTime =
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
} else
info_buf.LastWriteTime = 0;
/*
* Samba throws this field away, but windows may actually use it.
* Do not set ctime unless other time stamps are changed explicitly
* (i.e. by utimes()) since we would then have a mix of client and
* server times.
*/
if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
cFYI(1, ("CIFS - CTIME changed"));
info_buf.ChangeTime =
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
} else
info_buf.ChangeTime = 0;
info_buf.CreationTime = 0; /* don't change */
info_buf.Attributes = cpu_to_le32(dosattr);
/*
* If the file is already open for write, just use that fileid
*/
open_file = find_writable_file(cifsInode);
if (open_file) {
netfid = open_file->netfid;
netpid = open_file->pid;
goto set_via_filehandle;
}
/*
* NT4 apparently returns success on this call, but it doesn't
* really work.
*/
if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
&info_buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc != -EOPNOTSUPP && rc != -EINVAL)
goto out;
}
cFYI(1, ("calling SetFileInfo since SetPathInfo for "
"times not supported by this server"));
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
CREATE_NOT_DIR, &netfid, &oplock,
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc != 0) {
if (rc == -EIO)
rc = -EINVAL;
goto out;
}
netpid = current->tgid;
set_via_filehandle:
rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
if (open_file == NULL)
CIFSSMBClose(xid, pTcon, netfid);
else
atomic_dec(&open_file->wrtPending);
out:
return rc;
}
static int
cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
{ {
int rc;
int xid; int xid;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
int rc = -EACCES;
FILE_BASIC_INFO time_buf;
bool set_time = false;
bool set_dosattr = false;
__u64 mode = 0xFFFFFFFFFFFFFFFFULL;
__u64 uid = 0xFFFFFFFFFFFFFFFFULL;
__u64 gid = 0xFFFFFFFFFFFFFFFFULL;
struct cifsInodeInfo *cifsInode;
struct inode *inode = direntry->d_inode; struct inode *inode = direntry->d_inode;
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *pTcon = cifs_sb->tcon;
struct cifs_unix_set_info_args *args = NULL;
cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x",
direntry->d_name.name, attrs->ia_valid));
xid = GetXid();
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
/* check if we have permission to change attrs */
rc = inode_change_ok(inode, attrs);
if (rc < 0)
goto out;
else
rc = 0;
}
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
rc = -ENOMEM;
goto out;
}
if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
/*
Flush data before changing file size or changing the last
write time of the file on the server. If the
flush returns error, store it to report later and continue.
BB: This should be smarter. Why bother flushing pages that
will be truncated anyway? Also, should we error out here if
the flush returns error?
*/
rc = filemap_write_and_wait(inode->i_mapping);
if (rc != 0) {
cifsInode->write_behind_rc = rc;
rc = 0;
}
}
if (attrs->ia_valid & ATTR_SIZE) {
rc = cifs_set_file_size(inode, attrs, xid, full_path);
if (rc != 0)
goto out;
}
/* skip mode change if it's just for clearing setuid/setgid */
if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
attrs->ia_valid &= ~ATTR_MODE;
args = kmalloc(sizeof(*args), GFP_KERNEL);
if (args == NULL) {
rc = -ENOMEM;
goto out;
}
/* set up the struct */
if (attrs->ia_valid & ATTR_MODE)
args->mode = attrs->ia_mode;
else
args->mode = NO_CHANGE_64;
if (attrs->ia_valid & ATTR_UID)
args->uid = attrs->ia_uid;
else
args->uid = NO_CHANGE_64;
if (attrs->ia_valid & ATTR_GID)
args->gid = attrs->ia_gid;
else
args->gid = NO_CHANGE_64;
if (attrs->ia_valid & ATTR_ATIME)
args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
else
args->atime = NO_CHANGE_64;
if (attrs->ia_valid & ATTR_MTIME)
args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
else
args->mtime = NO_CHANGE_64;
if (attrs->ia_valid & ATTR_CTIME)
args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
else
args->ctime = NO_CHANGE_64;
args->device = 0;
rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc)
rc = inode_setattr(inode, attrs);
out:
kfree(args);
kfree(full_path);
FreeXid(xid);
return rc;
}
static int
cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
{
int xid;
struct inode *inode = direntry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
char *full_path = NULL;
int rc = -EACCES;
__u32 dosattr = 0;
__u64 mode = NO_CHANGE_64;
xid = GetXid(); xid = GetXid();
cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
direntry->d_name.name, attrs->ia_valid)); direntry->d_name.name, attrs->ia_valid));
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
/* check if we have permission to change attrs */ /* check if we have permission to change attrs */
rc = inode_change_ok(inode, attrs); rc = inode_change_ok(inode, attrs);
...@@ -1528,7 +1741,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1528,7 +1741,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
cifsInode = CIFS_I(inode);
if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
/* /*
...@@ -1559,21 +1771,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1559,21 +1771,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
* CIFSACL support + proper Windows to Unix idmapping, we may be * CIFSACL support + proper Windows to Unix idmapping, we may be
* able to support this in the future. * able to support this in the future.
*/ */
if (!pTcon->unix_ext && if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
} else {
if (attrs->ia_valid & ATTR_UID) {
cFYI(1, ("UID changed to %d", attrs->ia_uid));
uid = attrs->ia_uid;
}
if (attrs->ia_valid & ATTR_GID) {
cFYI(1, ("GID changed to %d", attrs->ia_gid));
gid = attrs->ia_gid;
}
}
time_buf.Attributes = 0;
/* skip mode change if it's just for clearing setuid/setgid */ /* skip mode change if it's just for clearing setuid/setgid */
if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
...@@ -1584,13 +1783,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1584,13 +1783,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
mode = attrs->ia_mode; mode = attrs->ia_mode;
} }
if ((pTcon->unix_ext) if (attrs->ia_valid & ATTR_MODE) {
&& (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
0 /* dev_t */, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
else if (attrs->ia_valid & ATTR_MODE) {
rc = 0; rc = 0;
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
...@@ -1599,24 +1792,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1599,24 +1792,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
#endif #endif
if (((mode & S_IWUGO) == 0) && if (((mode & S_IWUGO) == 0) &&
(cifsInode->cifsAttrs & ATTR_READONLY) == 0) { (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
set_dosattr = true;
time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs | dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
ATTR_READONLY);
/* fix up mode if we're not using dynperm */ /* fix up mode if we're not using dynperm */
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
attrs->ia_mode = inode->i_mode & ~S_IWUGO; attrs->ia_mode = inode->i_mode & ~S_IWUGO;
} else if ((mode & S_IWUGO) && } else if ((mode & S_IWUGO) &&
(cifsInode->cifsAttrs & ATTR_READONLY)) { (cifsInode->cifsAttrs & ATTR_READONLY)) {
/* If file is readonly on server, we would
not be able to write to it - so if any write dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
bit is enabled for user or group or other we /* Attributes of 0 are ignored */
need to at least try to remove r/o dos attr */ if (dosattr == 0)
set_dosattr = true; dosattr |= ATTR_NORMAL;
time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
(~ATTR_READONLY));
/* Windows ignores set to zero */
if (time_buf.Attributes == 0)
time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
/* reset local inode permissions to normal */ /* reset local inode permissions to normal */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
...@@ -1634,82 +1822,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1634,82 +1822,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
} }
} }
if (attrs->ia_valid & ATTR_ATIME) { if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
set_time = true; ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
time_buf.LastAccessTime = rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
} else
time_buf.LastAccessTime = 0;
if (attrs->ia_valid & ATTR_MTIME) {
set_time = true;
time_buf.LastWriteTime =
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
} else
time_buf.LastWriteTime = 0;
/* Do not set ctime explicitly unless other time
stamps are changed explicitly (i.e. by utime()
since we would then have a mix of client and
server times */
if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
set_time = true;
/* Although Samba throws this field away
it may be useful to Windows - but we do
not want to set ctime unless some other
timestamp is changing */
cFYI(1, ("CIFS - CTIME changed"));
time_buf.ChangeTime =
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
} else
time_buf.ChangeTime = 0;
if (set_time || set_dosattr) {
time_buf.CreationTime = 0; /* do not change */
/* In the future we should experiment - try setting timestamps
via Handle (SetFileInfo) instead of by path */
if (!(pTcon->ses->flags & CIFS_SES_NT4))
rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
else
rc = -EOPNOTSUPP;
if (rc == -EOPNOTSUPP) {
int oplock = 0;
__u16 netfid;
cFYI(1, ("calling SetFileInfo since SetPathInfo for "
"times not supported by this server"));
/* BB we could scan to see if we already have it open
and pass in pid of opener to function */
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
CREATE_NOT_DIR, &netfid, &oplock,
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == 0) {
rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
netfid);
CIFSSMBClose(xid, pTcon, netfid);
} else {
/* BB For even older servers we could convert time_buf
into old DOS style which uses two second
granularity */
/* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
&time_buf, cifs_sb->local_nls); */
}
}
/* Even if error on time set, no sense failing the call if /* Even if error on time set, no sense failing the call if
the server would set the time to a reasonable value anyway, the server would set the time to a reasonable value anyway,
and this check ensures that we are not being called from and this check ensures that we are not being called from
sys_utimes in which case we ought to fail the call back to sys_utimes in which case we ought to fail the call back to
the user when the server rejects the call */ the user when the server rejects the call */
if ((rc) && (attrs->ia_valid & if ((rc) && (attrs->ia_valid &
(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
rc = 0; rc = 0;
} }
...@@ -1723,6 +1847,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1723,6 +1847,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
return rc; return rc;
} }
int
cifs_setattr(struct dentry *direntry, struct iattr *attrs)
{
struct inode *inode = direntry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *pTcon = cifs_sb->tcon;
if (pTcon->unix_ext)
return cifs_setattr_unix(direntry, attrs);
return cifs_setattr_nounix(direntry, attrs);
/* BB: add cifs_setattr_legacy for really old servers */
}
#if 0 #if 0
void cifs_delete_inode(struct inode *inode) void cifs_delete_inode(struct inode *inode)
{ {
......
...@@ -265,6 +265,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -265,6 +265,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
cFYI(1, ("Sending smb: total_len %d", total_len)); cFYI(1, ("Sending smb: total_len %d", total_len));
dump_smb(smb_buffer, len); dump_smb(smb_buffer, len);
i = 0;
while (total_len) { while (total_len) {
rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
n_vec - first_vec, total_len); n_vec - first_vec, total_len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment