mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
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
This commit is contained in:
commit
56831a1a88
@ -1,3 +1,11 @@
|
||||
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
|
||||
------------
|
||||
DFS support added (Microsoft Distributed File System client support needed
|
||||
|
282
fs/cifs/asn1.c
282
fs/cifs/asn1.c
@ -483,6 +483,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
||||
|
||||
asn1_open(&ctx, security_blob, length);
|
||||
|
||||
/* GSSAPI header */
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding negTokenInit header"));
|
||||
return 0;
|
||||
@ -490,154 +491,143 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
||||
|| (tag != ASN1_EOC)) {
|
||||
cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag));
|
||||
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) {
|
||||
cFYI(1, ("Error decoding negTokenInit header"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|
||||
|| (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) {
|
||||
cFYI(1, ("Error decoding negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_SEQ)) {
|
||||
cFYI(1,
|
||||
("cls = %d con = %d tag = %d end = %p (%d) exit 1",
|
||||
cls, con, tag, end, *end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding 2nd part of negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|
||||
|| (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, &sequence_end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding 2nd part of negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_SEQ)) {
|
||||
cFYI(1,
|
||||
("cls = %d con = %d tag = %d end = %p (%d) exit 1",
|
||||
cls, con, tag, end, *end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!asn1_eoc_decode(&ctx, sequence_end)) {
|
||||
rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
|
||||
if (!rc) {
|
||||
cFYI(1,
|
||||
("Error decoding negTokenInit hdr exit2"));
|
||||
return 0;
|
||||
}
|
||||
if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
|
||||
if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
|
||||
|
||||
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) {
|
||||
cFYI(1,
|
||||
("Error decoding last part negTokenInit exit3"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
|
||||
/* tag = 3 indicating mechListMIC */
|
||||
cFYI(1,
|
||||
("Exit 4 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 exit5"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_SEQ)) {
|
||||
cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",
|
||||
cls, con, tag, end, *end));
|
||||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1,
|
||||
("Error decoding last part negTokenInit exit 7"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
|
||||
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? */
|
||||
}
|
||||
|
||||
/* Check for SPNEGO OID -- remember to free obj->oid */
|
||||
rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
|
||||
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;
|
||||
}
|
||||
|
||||
/* SPNEGO OID not present or garbled -- bail out */
|
||||
if (!rc) {
|
||||
cFYI(1, ("Error decoding negTokenInit header"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|
||||
|| (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) {
|
||||
cFYI(1, ("Error decoding negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_SEQ)) {
|
||||
cFYI(1,
|
||||
("cls = %d con = %d tag = %d end = %p (%d) exit 1",
|
||||
cls, con, tag, end, *end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding 2nd part of negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|
||||
|| (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, &sequence_end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding 2nd part of negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_SEQ)) {
|
||||
cFYI(1,
|
||||
("cls = %d con = %d tag = %d end = %p (%d) exit 1",
|
||||
cls, con, tag, end, *end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!asn1_eoc_decode(&ctx, sequence_end)) {
|
||||
rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
|
||||
if (!rc) {
|
||||
cFYI(1,
|
||||
("Error decoding negTokenInit hdr exit2"));
|
||||
return 0;
|
||||
}
|
||||
if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
|
||||
if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
|
||||
|
||||
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) {
|
||||
cFYI(1, ("Error decoding last part negTokenInit exit3"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
|
||||
/* tag = 3 indicating mechListMIC */
|
||||
cFYI(1, ("Exit 4 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 exit5"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_SEQ)) {
|
||||
cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",
|
||||
cls, con, tag, end, *end));
|
||||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding last part negTokenInit exit 7"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
|
||||
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)
|
||||
*secType = Kerberos;
|
||||
else if (use_ntlmssp)
|
||||
|
@ -79,27 +79,25 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_for_each(tmp, &server->pending_mid_q) {
|
||||
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",
|
||||
mid_entry->midState,
|
||||
(int)mid_entry->command,
|
||||
mid_entry->pid,
|
||||
mid_entry->tsk,
|
||||
mid_entry->mid));
|
||||
cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
|
||||
mid_entry->midState,
|
||||
(int)mid_entry->command,
|
||||
mid_entry->pid,
|
||||
mid_entry->tsk,
|
||||
mid_entry->mid));
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld",
|
||||
mid_entry->largeBuf,
|
||||
mid_entry->resp_buf,
|
||||
mid_entry->when_received,
|
||||
jiffies));
|
||||
cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld",
|
||||
mid_entry->largeBuf,
|
||||
mid_entry->resp_buf,
|
||||
mid_entry->when_received,
|
||||
jiffies));
|
||||
#endif /* STATS2 */
|
||||
cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
|
||||
mid_entry->multiEnd));
|
||||
if (mid_entry->resp_buf) {
|
||||
cifs_dump_detail(mid_entry->resp_buf);
|
||||
cifs_dump_mem("existing buf: ",
|
||||
mid_entry->resp_buf, 62);
|
||||
}
|
||||
cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
|
||||
mid_entry->multiEnd));
|
||||
if (mid_entry->resp_buf) {
|
||||
cifs_dump_detail(mid_entry->resp_buf);
|
||||
cifs_dump_mem("existing buf: ",
|
||||
mid_entry->resp_buf, 62);
|
||||
}
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
@ -163,16 +161,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
mid_entry = list_entry(tmp1, struct
|
||||
mid_q_entry,
|
||||
qhead);
|
||||
if (mid_entry) {
|
||||
seq_printf(m,
|
||||
"State: %d com: %d pid:"
|
||||
" %d tsk: %p mid %d\n",
|
||||
mid_entry->midState,
|
||||
(int)mid_entry->command,
|
||||
mid_entry->pid,
|
||||
mid_entry->tsk,
|
||||
mid_entry->mid);
|
||||
}
|
||||
seq_printf(m, "State: %d com: %d pid:"
|
||||
" %d tsk: %p mid %d\n",
|
||||
mid_entry->midState,
|
||||
(int)mid_entry->command,
|
||||
mid_entry->pid,
|
||||
mid_entry->tsk,
|
||||
mid_entry->mid);
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
|
@ -66,8 +66,8 @@ struct key_type cifs_spnego_key_type = {
|
||||
.describe = user_describe,
|
||||
};
|
||||
|
||||
#define MAX_VER_STR_LEN 9 /* length of longest version string e.g.
|
||||
strlen(";ver=0xFF") */
|
||||
#define MAX_VER_STR_LEN 8 /* length of longest version string e.g.
|
||||
strlen("ver=0xFF") */
|
||||
#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
|
||||
in future could have strlen(";sec=ntlmsspi") */
|
||||
#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)
|
||||
struct key *spnego_key;
|
||||
const char *hostname = server->hostname;
|
||||
|
||||
/* BB: come up with better scheme for determining length */
|
||||
/* length of fields (with semicolons): ver=0xyz ipv4= ipaddress host=
|
||||
hostname sec=mechanism uid=0x uid */
|
||||
desc_len = MAX_VER_STR_LEN + 5 + MAX_IPV6_ADDR_LEN + 1 + 6 +
|
||||
strlen(hostname) + MAX_MECH_STR_LEN + 8 + (sizeof(uid_t) * 2);
|
||||
/* length of fields (with semicolons): ver=0xyz ip4=ipaddress
|
||||
host=hostname sec=mechanism uid=0xFF user=username */
|
||||
desc_len = MAX_VER_STR_LEN +
|
||||
6 /* len of "host=" */ + strlen(hostname) +
|
||||
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);
|
||||
description = kzalloc(desc_len, GFP_KERNEL);
|
||||
if (description == NULL)
|
||||
|
@ -930,36 +930,34 @@ static int cifs_oplock_thread(void *dummyarg)
|
||||
schedule_timeout(39*HZ);
|
||||
} else {
|
||||
oplock_item = list_entry(GlobalOplock_Q.next,
|
||||
struct oplock_q_entry, qhead);
|
||||
if (oplock_item) {
|
||||
cFYI(1, ("found oplock item to write out"));
|
||||
pTcon = oplock_item->tcon;
|
||||
inode = oplock_item->pinode;
|
||||
netfid = oplock_item->netfid;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
DeleteOplockQEntry(oplock_item);
|
||||
/* can not grab inode sem here since it would
|
||||
struct oplock_q_entry, qhead);
|
||||
cFYI(1, ("found oplock item to write out"));
|
||||
pTcon = oplock_item->tcon;
|
||||
inode = oplock_item->pinode;
|
||||
netfid = oplock_item->netfid;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
DeleteOplockQEntry(oplock_item);
|
||||
/* can not grab inode sem here since it would
|
||||
deadlock when oplock received on delete
|
||||
since vfs_unlink holds the i_mutex across
|
||||
the call */
|
||||
/* mutex_lock(&inode->i_mutex);*/
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
rc =
|
||||
filemap_fdatawrite(inode->i_mapping);
|
||||
if (CIFS_I(inode)->clientCanCacheRead
|
||||
== 0) {
|
||||
waitrc = filemap_fdatawait(inode->i_mapping);
|
||||
invalidate_remote_inode(inode);
|
||||
}
|
||||
if (rc == 0)
|
||||
rc = waitrc;
|
||||
} else
|
||||
rc = 0;
|
||||
/* mutex_unlock(&inode->i_mutex);*/
|
||||
if (rc)
|
||||
CIFS_I(inode)->write_behind_rc = rc;
|
||||
cFYI(1, ("Oplock flush inode %p rc %d",
|
||||
inode, rc));
|
||||
/* mutex_lock(&inode->i_mutex);*/
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
rc = filemap_fdatawrite(inode->i_mapping);
|
||||
if (CIFS_I(inode)->clientCanCacheRead == 0) {
|
||||
waitrc = filemap_fdatawait(
|
||||
inode->i_mapping);
|
||||
invalidate_remote_inode(inode);
|
||||
}
|
||||
if (rc == 0)
|
||||
rc = waitrc;
|
||||
} else
|
||||
rc = 0;
|
||||
/* mutex_unlock(&inode->i_mutex);*/
|
||||
if (rc)
|
||||
CIFS_I(inode)->write_behind_rc = rc;
|
||||
cFYI(1, ("Oplock flush inode %p rc %d",
|
||||
inode, rc));
|
||||
|
||||
/* releasing stale oplock after recent reconnect
|
||||
of smb session using a now incorrect file
|
||||
@ -967,15 +965,13 @@ static int cifs_oplock_thread(void *dummyarg)
|
||||
not bother sending an oplock release if session
|
||||
to server still is disconnected since oplock
|
||||
already released by the server in that case */
|
||||
if (pTcon->tidStatus != CifsNeedReconnect) {
|
||||
rc = CIFSSMBLock(0, pTcon, netfid,
|
||||
0 /* len */ , 0 /* offset */, 0,
|
||||
0, LOCKING_ANDX_OPLOCK_RELEASE,
|
||||
false /* wait flag */);
|
||||
cFYI(1, ("Oplock release rc = %d", rc));
|
||||
}
|
||||
} else
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
if (pTcon->tidStatus != CifsNeedReconnect) {
|
||||
rc = CIFSSMBLock(0, pTcon, netfid,
|
||||
0 /* len */ , 0 /* offset */, 0,
|
||||
0, LOCKING_ANDX_OPLOCK_RELEASE,
|
||||
false /* wait flag */);
|
||||
cFYI(1, ("Oplock release rc = %d", rc));
|
||||
}
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(1); /* yield in case q were corrupt */
|
||||
}
|
||||
@ -1001,8 +997,7 @@ static int cifs_dnotify_thread(void *dummyarg)
|
||||
list_for_each(tmp, &GlobalSMBSessionList) {
|
||||
ses = list_entry(tmp, struct cifsSesInfo,
|
||||
cifsSessionList);
|
||||
if (ses && ses->server &&
|
||||
atomic_read(&ses->server->inFlight))
|
||||
if (ses->server && atomic_read(&ses->server->inFlight))
|
||||
wake_up_all(&ses->server->response_q);
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
|
@ -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;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.53"
|
||||
#define CIFS_VERSION "1.54"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -262,7 +262,7 @@
|
||||
*/
|
||||
#define CIFS_NO_HANDLE 0xFFFF
|
||||
|
||||
#define NO_CHANGE_64 cpu_to_le64(0xFFFFFFFFFFFFFFFFULL)
|
||||
#define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL
|
||||
#define NO_CHANGE_32 0xFFFFFFFFUL
|
||||
|
||||
/* IPC$ in ASCII */
|
||||
|
@ -172,12 +172,13 @@ extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon);
|
||||
extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
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 struct nls_table *nls_codepage,
|
||||
int remap_special_chars);
|
||||
extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
|
||||
const FILE_BASIC_INFO *data, __u16 fid);
|
||||
extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
const FILE_BASIC_INFO *data, __u16 fid,
|
||||
__u32 pid_of_opener);
|
||||
#if 0
|
||||
extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
|
||||
char *fileName, __u16 dos_attributes,
|
||||
@ -191,9 +192,20 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
|
||||
extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
|
||||
__u64 size, __u16 fileHandle, __u32 opener_pid,
|
||||
bool AllocSizeFlag);
|
||||
extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
|
||||
char *full_path, __u64 mode, __u64 uid,
|
||||
__u64 gid, dev_t dev,
|
||||
|
||||
struct cifs_unix_set_info_args {
|
||||
__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,
|
||||
int remap_special_chars);
|
||||
|
||||
|
@ -128,8 +128,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
|
||||
open_file = list_entry(tmp, struct cifsFileInfo, tlist);
|
||||
if (open_file)
|
||||
open_file->invalidHandle = true;
|
||||
open_file->invalidHandle = true;
|
||||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
/* BB Add call to invalidate_inodes(sb) for all superblocks mounted
|
||||
@ -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
|
||||
DOS time format with 2 second granularity */
|
||||
int
|
||||
CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
|
||||
const FILE_BASIC_INFO *data, __u16 fid)
|
||||
CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
|
||||
{
|
||||
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
||||
char *data_offset;
|
||||
@ -4830,11 +4829,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* At this point there is no need to override the current pid
|
||||
with the pid of the opener, but that could change if we someday
|
||||
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));*/
|
||||
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
|
||||
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
|
||||
|
||||
params = 6;
|
||||
pSMB->MaxSetupCount = 0;
|
||||
@ -4882,9 +4878,9 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
|
||||
|
||||
|
||||
int
|
||||
CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
|
||||
const FILE_BASIC_INFO *data,
|
||||
const struct nls_table *nls_codepage, int remap)
|
||||
CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
const char *fileName, const FILE_BASIC_INFO *data,
|
||||
const struct nls_table *nls_codepage, int remap)
|
||||
{
|
||||
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
||||
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
||||
@ -5013,10 +5009,9 @@ SetAttrLgcyRetry:
|
||||
#endif /* temporarily unneeded SetAttr legacy function */
|
||||
|
||||
int
|
||||
CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
|
||||
char *fileName, __u64 mode, __u64 uid, __u64 gid,
|
||||
dev_t device, const struct nls_table *nls_codepage,
|
||||
int remap)
|
||||
CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
|
||||
const struct cifs_unix_set_info_args *args,
|
||||
const struct nls_table *nls_codepage, int remap)
|
||||
{
|
||||
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
||||
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
||||
@ -5025,6 +5020,7 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
|
||||
int bytes_returned = 0;
|
||||
FILE_UNIX_BASIC_INFO *data_offset;
|
||||
__u16 params, param_offset, offset, count, byte_count;
|
||||
__u64 mode = args->mode;
|
||||
|
||||
cFYI(1, ("In SetUID/GID/Mode"));
|
||||
setPermsRetry:
|
||||
@ -5080,16 +5076,16 @@ setPermsRetry:
|
||||
set file size and do not want to truncate file size to zero
|
||||
accidently as happened on one Samba server beta by putting
|
||||
zero instead of -1 here */
|
||||
data_offset->EndOfFile = NO_CHANGE_64;
|
||||
data_offset->NumOfBytes = NO_CHANGE_64;
|
||||
data_offset->LastStatusChange = NO_CHANGE_64;
|
||||
data_offset->LastAccessTime = NO_CHANGE_64;
|
||||
data_offset->LastModificationTime = NO_CHANGE_64;
|
||||
data_offset->Uid = cpu_to_le64(uid);
|
||||
data_offset->Gid = cpu_to_le64(gid);
|
||||
data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
|
||||
data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
|
||||
data_offset->LastStatusChange = cpu_to_le64(args->ctime);
|
||||
data_offset->LastAccessTime = cpu_to_le64(args->atime);
|
||||
data_offset->LastModificationTime = cpu_to_le64(args->mtime);
|
||||
data_offset->Uid = cpu_to_le64(args->uid);
|
||||
data_offset->Gid = cpu_to_le64(args->gid);
|
||||
/* better to leave device as zero when it is */
|
||||
data_offset->DevMajor = cpu_to_le64(MAJOR(device));
|
||||
data_offset->DevMinor = cpu_to_le64(MINOR(device));
|
||||
data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
|
||||
data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
|
||||
data_offset->Permissions = cpu_to_le64(mode);
|
||||
|
||||
if (S_ISREG(mode))
|
||||
|
@ -151,7 +151,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||
}
|
||||
list_for_each(tmp, &GlobalTreeConnectionList) {
|
||||
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;
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
@ -173,14 +173,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||
mid_entry = list_entry(tmp, struct
|
||||
mid_q_entry,
|
||||
qhead);
|
||||
if (mid_entry) {
|
||||
if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
|
||||
if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
|
||||
/* Mark other intransit requests as needing
|
||||
retry so we do not immediately mark the
|
||||
session bad again (ie after we reconnect
|
||||
below) as they timeout too */
|
||||
mid_entry->midState = MID_RETRY_NEEDED;
|
||||
}
|
||||
mid_entry->midState = MID_RETRY_NEEDED;
|
||||
}
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
@ -351,11 +349,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||
|
||||
current->flags |= PF_MEMALLOC;
|
||||
cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
atomic_inc(&tcpSesAllocCount);
|
||||
length = tcpSesAllocCount.counter;
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
if (length > 1)
|
||||
|
||||
length = atomic_inc_return(&tcpSesAllocCount);
|
||||
if (length > 1)
|
||||
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
|
||||
GFP_KERNEL);
|
||||
|
||||
@ -745,14 +741,11 @@ multi_t2_fnd:
|
||||
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
|
||||
if there are any pointing to this (e.g
|
||||
if a crazy root user tried to kill cifsd
|
||||
kernel thread explicitly this might happen) */
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &GlobalSMBSessionList) {
|
||||
ses = list_entry(tmp, struct cifsSesInfo,
|
||||
cifsSessionList);
|
||||
@ -763,6 +756,8 @@ multi_t2_fnd:
|
||||
|
||||
kfree(server->hostname);
|
||||
kfree(server);
|
||||
|
||||
length = atomic_dec_return(&tcpSesAllocCount);
|
||||
if (length > 0)
|
||||
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
|
||||
GFP_KERNEL);
|
||||
@ -3623,97 +3618,91 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
||||
}
|
||||
first_time = 1;
|
||||
}
|
||||
if (!rc) {
|
||||
pSesInfo->flags = 0;
|
||||
pSesInfo->capabilities = pSesInfo->server->capabilities;
|
||||
if (linuxExtEnabled == 0)
|
||||
pSesInfo->capabilities &= (~CAP_UNIX);
|
||||
|
||||
if (rc)
|
||||
goto ss_err_exit;
|
||||
|
||||
pSesInfo->flags = 0;
|
||||
pSesInfo->capabilities = pSesInfo->server->capabilities;
|
||||
if (linuxExtEnabled == 0)
|
||||
pSesInfo->capabilities &= (~CAP_UNIX);
|
||||
/* pSesInfo->sequence_number = 0;*/
|
||||
cFYI(1,
|
||||
("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
|
||||
pSesInfo->server->secMode,
|
||||
pSesInfo->server->capabilities,
|
||||
pSesInfo->server->timeAdj));
|
||||
if (experimEnabled < 2)
|
||||
rc = CIFS_SessSetup(xid, pSesInfo,
|
||||
first_time, nls_info);
|
||||
else if (extended_security
|
||||
&& (pSesInfo->capabilities
|
||||
& CAP_EXTENDED_SECURITY)
|
||||
&& (pSesInfo->server->secType == NTLMSSP)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
} else if (extended_security
|
||||
&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
|
||||
&& (pSesInfo->server->secType == RawNTLMSSP)) {
|
||||
cFYI(1, ("NTLMSSP sesssetup"));
|
||||
rc = CIFSNTLMSSPNegotiateSessSetup(xid,
|
||||
pSesInfo,
|
||||
&ntlmv2_flag,
|
||||
nls_info);
|
||||
if (!rc) {
|
||||
if (ntlmv2_flag) {
|
||||
char *v2_response;
|
||||
cFYI(1, ("more secure NTLM ver2 hash"));
|
||||
if (CalcNTLMv2_partial_mac_key(pSesInfo,
|
||||
nls_info)) {
|
||||
rc = -ENOMEM;
|
||||
goto ss_err_exit;
|
||||
} else
|
||||
v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
|
||||
if (v2_response) {
|
||||
CalcNTLMv2_response(pSesInfo,
|
||||
v2_response);
|
||||
/* if (first_time)
|
||||
cifs_calculate_ntlmv2_mac_key(
|
||||
pSesInfo->server->mac_signing_key,
|
||||
response, ntlm_session_key,*/
|
||||
kfree(v2_response);
|
||||
cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
|
||||
pSesInfo->server->secMode,
|
||||
pSesInfo->server->capabilities,
|
||||
pSesInfo->server->timeAdj));
|
||||
if (experimEnabled < 2)
|
||||
rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
|
||||
else if (extended_security
|
||||
&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
|
||||
&& (pSesInfo->server->secType == NTLMSSP)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
} else if (extended_security
|
||||
&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
|
||||
&& (pSesInfo->server->secType == RawNTLMSSP)) {
|
||||
cFYI(1, ("NTLMSSP sesssetup"));
|
||||
rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
|
||||
nls_info);
|
||||
if (!rc) {
|
||||
if (ntlmv2_flag) {
|
||||
char *v2_response;
|
||||
cFYI(1, ("more secure NTLM ver2 hash"));
|
||||
if (CalcNTLMv2_partial_mac_key(pSesInfo,
|
||||
nls_info)) {
|
||||
rc = -ENOMEM;
|
||||
goto ss_err_exit;
|
||||
} else
|
||||
v2_response = kmalloc(16 + 64 /* blob*/,
|
||||
GFP_KERNEL);
|
||||
if (v2_response) {
|
||||
CalcNTLMv2_response(pSesInfo,
|
||||
v2_response);
|
||||
/* if (first_time)
|
||||
cifs_calculate_ntlmv2_mac_key */
|
||||
kfree(v2_response);
|
||||
/* BB Put dummy sig in SessSetup PDU? */
|
||||
} else {
|
||||
rc = -ENOMEM;
|
||||
goto ss_err_exit;
|
||||
}
|
||||
|
||||
} 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);
|
||||
rc = -ENOMEM;
|
||||
goto ss_err_exit;
|
||||
}
|
||||
|
||||
} 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
|
||||
in AuthSessSetup so we no longer calculate it */
|
||||
|
||||
rc = CIFSNTLMSSPAuthSessSetup(xid,
|
||||
pSesInfo,
|
||||
ntlm_session_key,
|
||||
ntlmv2_flag,
|
||||
nls_info);
|
||||
}
|
||||
} else { /* old style NTLM 0.12 session setup */
|
||||
SMBNTencrypt(pSesInfo->password,
|
||||
pSesInfo->server->cryptKey,
|
||||
ntlm_session_key);
|
||||
rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
|
||||
ntlm_session_key,
|
||||
ntlmv2_flag,
|
||||
nls_info);
|
||||
}
|
||||
} else { /* old style NTLM 0.12 session setup */
|
||||
SMBNTencrypt(pSesInfo->password, pSesInfo->server->cryptKey,
|
||||
ntlm_session_key);
|
||||
|
||||
if (first_time)
|
||||
cifs_calculate_mac_key(
|
||||
if (first_time)
|
||||
cifs_calculate_mac_key(
|
||||
&pSesInfo->server->mac_signing_key,
|
||||
ntlm_session_key, pSesInfo->password);
|
||||
|
||||
rc = CIFSSessSetup(xid, pSesInfo,
|
||||
ntlm_session_key, nls_info);
|
||||
}
|
||||
if (rc) {
|
||||
cERROR(1, ("Send error in SessSetup = %d", rc));
|
||||
} else {
|
||||
cFYI(1, ("CIFS Session Established successfully"));
|
||||
pSesInfo->status = CifsGood;
|
||||
}
|
||||
rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
|
||||
}
|
||||
if (rc) {
|
||||
cERROR(1, ("Send error in SessSetup = %d", rc));
|
||||
} else {
|
||||
cFYI(1, ("CIFS Session Established successfully"));
|
||||
pSesInfo->status = CifsGood;
|
||||
}
|
||||
|
||||
ss_err_exit:
|
||||
return rc;
|
||||
}
|
||||
|
@ -226,23 +226,28 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
/* If Open reported that we actually created a file
|
||||
then we now have to set the mode if possible */
|
||||
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) {
|
||||
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
|
||||
(__u64)current->fsuid,
|
||||
(__u64)current->fsgid,
|
||||
0 /* dev */,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
args.uid = (__u64) current->fsuid;
|
||||
if (inode->i_mode & S_ISGID)
|
||||
args.gid = (__u64) inode->i_gid;
|
||||
else
|
||||
args.gid = (__u64) current->fsgid;
|
||||
} else {
|
||||
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
|
||||
(__u64)-1,
|
||||
(__u64)-1,
|
||||
0 /* dev */,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
} else {
|
||||
/* BB implement mode setting via Windows security
|
||||
descriptors e.g. */
|
||||
@ -267,7 +272,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
(cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_SET_UID)) {
|
||||
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,
|
||||
if (full_path == NULL)
|
||||
rc = -ENOMEM;
|
||||
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) {
|
||||
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
|
||||
mode, (__u64)current->fsuid,
|
||||
(__u64)current->fsgid,
|
||||
device_number, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
args.uid = (__u64) current->fsuid;
|
||||
args.gid = (__u64) current->fsgid;
|
||||
} else {
|
||||
rc = CIFSSMBUnixSetPerms(xid, pTcon,
|
||||
full_path, mode, (__u64)-1, (__u64)-1,
|
||||
device_number, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
|
||||
&args, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
|
||||
if (!rc) {
|
||||
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
||||
|
@ -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
|
||||
problems creating new read-only files */
|
||||
if (pTcon->unix_ext) {
|
||||
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
|
||||
inode->i_mode,
|
||||
(__u64)-1, (__u64)-1, 0 /* dev */,
|
||||
struct cifs_unix_set_info_args args = {
|
||||
.mode = inode->i_mode,
|
||||
.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->mnt_cifs_flags &
|
||||
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 */
|
||||
}
|
||||
}
|
||||
|
||||
|
419
fs/cifs/inode.c
419
fs/cifs/inode.c
@ -737,7 +737,7 @@ psx_del_no_retry:
|
||||
/* ATTRS set to normal clears r/o bit */
|
||||
pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
|
||||
if (!(pTcon->ses->flags & CIFS_SES_NT4))
|
||||
rc = CIFSSMBSetTimes(xid, pTcon, full_path,
|
||||
rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
|
||||
pinfo_buf,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
@ -767,9 +767,10 @@ psx_del_no_retry:
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc == 0) {
|
||||
rc = CIFSSMBSetFileTimes(xid, pTcon,
|
||||
pinfo_buf,
|
||||
netfid);
|
||||
rc = CIFSSMBSetFileInfo(xid, pTcon,
|
||||
pinfo_buf,
|
||||
netfid,
|
||||
current->tgid);
|
||||
CIFSSMBClose(xid, pTcon, netfid);
|
||||
}
|
||||
}
|
||||
@ -984,32 +985,41 @@ mkdir_get_info:
|
||||
* failed to get it from the server or was set bogus */
|
||||
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
|
||||
direntry->d_inode->i_nlink = 2;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
|
||||
mode,
|
||||
(__u64)current->fsuid,
|
||||
(__u64)current->fsgid,
|
||||
0 /* dev_t */,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
args.uid = (__u64)current->fsuid;
|
||||
if (inode->i_mode & S_ISGID)
|
||||
args.gid = (__u64)inode->i_gid;
|
||||
else
|
||||
args.gid = (__u64)current->fsgid;
|
||||
} else {
|
||||
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
|
||||
mode, (__u64)-1,
|
||||
(__u64)-1, 0 /* dev_t */,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
} else {
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
|
||||
(mode & S_IWUGO) == 0) {
|
||||
FILE_BASIC_INFO pInfo;
|
||||
memset(&pInfo, 0, sizeof(pInfo));
|
||||
pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
|
||||
CIFSSMBSetTimes(xid, pTcon, full_path,
|
||||
CIFSSMBSetPathInfo(xid, pTcon, full_path,
|
||||
&pInfo, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
@ -1024,8 +1034,12 @@ mkdir_get_info:
|
||||
CIFS_MOUNT_SET_UID) {
|
||||
direntry->d_inode->i_uid =
|
||||
current->fsuid;
|
||||
direntry->d_inode->i_gid =
|
||||
current->fsgid;
|
||||
if (inode->i_mode & S_ISGID)
|
||||
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)
|
||||
/* if (S_ISDIR(direntry->d_inode->i_mode))
|
||||
shrink_dcache_parent(direntry); */
|
||||
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);
|
||||
if (wbrc)
|
||||
CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
|
||||
}
|
||||
/* may eventually have to do this for open files too */
|
||||
if (list_empty(&(cifsInode->openFileList))) {
|
||||
/* changed on server - flush read ahead pages */
|
||||
@ -1489,30 +1504,228 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
|
||||
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;
|
||||
char *full_path = NULL;
|
||||
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 cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
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;
|
||||
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;
|
||||
__u32 dosattr = 0;
|
||||
__u64 mode = NO_CHANGE_64;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
|
||||
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) {
|
||||
/* check if we have permission to change attrs */
|
||||
rc = inode_change_ok(inode, attrs);
|
||||
@ -1528,7 +1741,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
FreeXid(xid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
cifsInode = CIFS_I(inode);
|
||||
|
||||
if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
|
||||
/*
|
||||
@ -1559,21 +1771,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
* CIFSACL support + proper Windows to Unix idmapping, we may be
|
||||
* able to support this in the future.
|
||||
*/
|
||||
if (!pTcon->unix_ext &&
|
||||
!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
|
||||
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 */
|
||||
if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
|
||||
@ -1584,13 +1783,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
mode = attrs->ia_mode;
|
||||
}
|
||||
|
||||
if ((pTcon->unix_ext)
|
||||
&& (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) {
|
||||
if (attrs->ia_valid & ATTR_MODE) {
|
||||
rc = 0;
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
|
||||
@ -1599,24 +1792,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
#endif
|
||||
if (((mode & S_IWUGO) == 0) &&
|
||||
(cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
|
||||
set_dosattr = true;
|
||||
time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs |
|
||||
ATTR_READONLY);
|
||||
|
||||
dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
|
||||
|
||||
/* fix up mode if we're not using dynperm */
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
|
||||
attrs->ia_mode = inode->i_mode & ~S_IWUGO;
|
||||
} else if ((mode & S_IWUGO) &&
|
||||
(cifsInode->cifsAttrs & ATTR_READONLY)) {
|
||||
/* If file is readonly on server, we would
|
||||
not be able to write to it - so if any write
|
||||
bit is enabled for user or group or other we
|
||||
need to at least try to remove r/o dos attr */
|
||||
set_dosattr = true;
|
||||
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);
|
||||
|
||||
dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
|
||||
/* Attributes of 0 are ignored */
|
||||
if (dosattr == 0)
|
||||
dosattr |= ATTR_NORMAL;
|
||||
|
||||
/* reset local inode permissions to normal */
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
|
||||
@ -1634,82 +1822,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
}
|
||||
}
|
||||
|
||||
if (attrs->ia_valid & ATTR_ATIME) {
|
||||
set_time = true;
|
||||
time_buf.LastAccessTime =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
|
||||
} else
|
||||
time_buf.LastAccessTime = 0;
|
||||
if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
|
||||
((attrs->ia_valid & ATTR_MODE) && dosattr)) {
|
||||
rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
|
||||
/* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
|
||||
|
||||
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
|
||||
the server would set the time to a reasonable value anyway,
|
||||
and this check ensures that we are not being called from
|
||||
sys_utimes in which case we ought to fail the call back to
|
||||
the user when the server rejects the call */
|
||||
if ((rc) && (attrs->ia_valid &
|
||||
(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
|
||||
(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
@ -1723,6 +1847,21 @@ cifs_setattr_exit:
|
||||
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
|
||||
void cifs_delete_inode(struct inode *inode)
|
||||
{
|
||||
|
@ -265,6 +265,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
|
||||
cFYI(1, ("Sending smb: total_len %d", total_len));
|
||||
dump_smb(smb_buffer, len);
|
||||
|
||||
i = 0;
|
||||
while (total_len) {
|
||||
rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
|
||||
n_vec - first_vec, total_len);
|
||||
|
Loading…
Reference in New Issue
Block a user