aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifs_fs_sb.h1
-rw-r--r--fs/cifs/cifsglob.h10
-rw-r--r--fs/cifs/cifspdu.h46
-rw-r--r--fs/cifs/cifsproto.h7
-rw-r--r--fs/cifs/cifssmb.c90
-rw-r--r--fs/cifs/connect.c20
-rw-r--r--fs/cifs/dir.c10
-rw-r--r--fs/cifs/fcntl.c2
-rw-r--r--fs/cifs/file.c4
-rw-r--r--fs/cifs/inode.c14
-rw-r--r--fs/cifs/link.c15
-rw-r--r--fs/cifs/readdir.c20
-rw-r--r--fs/cifs/xattr.c8
13 files changed, 207 insertions, 40 deletions
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index ec00d61d5308..5dc5fe6b486d 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -24,6 +24,7 @@
24#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ 24#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
25#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ 25#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
26#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ 26#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
27#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
27 28
28struct cifs_sb_info { 29struct cifs_sb_info {
29 struct cifsTconInfo *tcon; /* primary mount */ 30 struct cifsTconInfo *tcon; /* primary mount */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 81babab265e1..d3773e57acf9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -219,6 +219,9 @@ struct cifsTconInfo {
219 atomic_t num_rmdirs; 219 atomic_t num_rmdirs;
220 atomic_t num_renames; 220 atomic_t num_renames;
221 atomic_t num_t2renames; 221 atomic_t num_t2renames;
222 atomic_t num_ffirst;
223 atomic_t num_fnext;
224 atomic_t num_fclose;
222 __u64 bytes_read; 225 __u64 bytes_read;
223 __u64 bytes_written; 226 __u64 bytes_written;
224 spinlock_t stat_lock; 227 spinlock_t stat_lock;
@@ -306,6 +309,13 @@ CIFS_SB(struct super_block *sb)
306 return sb->s_fs_info; 309 return sb->s_fs_info;
307} 310}
308 311
312static inline const char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
313{
314 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
315 return '/';
316 else
317 return '\\';
318}
309 319
310/* one of these for every pending CIFS request to the server */ 320/* one of these for every pending CIFS request to the server */
311struct mid_q_entry { 321struct mid_q_entry {
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index aede6a813167..84d37f8e986e 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -59,6 +59,7 @@
59#define TRANS2_FIND_FIRST 0x01 59#define TRANS2_FIND_FIRST 0x01
60#define TRANS2_FIND_NEXT 0x02 60#define TRANS2_FIND_NEXT 0x02
61#define TRANS2_QUERY_FS_INFORMATION 0x03 61#define TRANS2_QUERY_FS_INFORMATION 0x03
62#define TRANS2_SET_FS_INFORMATION 0x04
62#define TRANS2_QUERY_PATH_INFORMATION 0x05 63#define TRANS2_QUERY_PATH_INFORMATION 0x05
63#define TRANS2_SET_PATH_INFORMATION 0x06 64#define TRANS2_SET_PATH_INFORMATION 0x06
64#define TRANS2_QUERY_FILE_INFORMATION 0x07 65#define TRANS2_QUERY_FILE_INFORMATION 0x07
@@ -1411,6 +1412,43 @@ typedef struct smb_com_transaction_qfsi_rsp {
1411 __u8 Pad; /* may be three bytes *//* followed by data area */ 1412 __u8 Pad; /* may be three bytes *//* followed by data area */
1412} TRANSACTION2_QFSI_RSP; 1413} TRANSACTION2_QFSI_RSP;
1413 1414
1415
1416/* SETFSInfo Levels */
1417#define SMB_SET_CIFS_UNIX_INFO 0x200
1418typedef struct smb_com_transaction2_setfsi_req {
1419 struct smb_hdr hdr; /* wct = 15 */
1420 __le16 TotalParameterCount;
1421 __le16 TotalDataCount;
1422 __le16 MaxParameterCount;
1423 __le16 MaxDataCount;
1424 __u8 MaxSetupCount;
1425 __u8 Reserved;
1426 __le16 Flags;
1427 __le32 Timeout;
1428 __u16 Reserved2;
1429 __le16 ParameterCount; /* 4 */
1430 __le16 ParameterOffset;
1431 __le16 DataCount; /* 12 */
1432 __le16 DataOffset;
1433 __u8 SetupCount; /* one */
1434 __u8 Reserved3;
1435 __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */
1436 __le16 ByteCount;
1437 __u8 Pad;
1438 __u16 FileNum; /* Parameters start. */
1439 __le16 InformationLevel;/* Parameters end. */
1440 __le16 ClientUnixMajor; /* Data start. */
1441 __le16 ClientUnixMinor;
1442 __le64 ClientUnixCap; /* Data end */
1443} TRANSACTION2_SETFSI_REQ;
1444
1445typedef struct smb_com_transaction2_setfsi_rsp {
1446 struct smb_hdr hdr; /* wct = 10 */
1447 struct trans2_resp t2;
1448 __u16 ByteCount;
1449} TRANSACTION2_SETFSI_RSP;
1450
1451
1414typedef struct smb_com_transaction2_get_dfs_refer_req { 1452typedef struct smb_com_transaction2_get_dfs_refer_req {
1415 struct smb_hdr hdr; /* wct = 15 */ 1453 struct smb_hdr hdr; /* wct = 15 */
1416 __le16 TotalParameterCount; 1454 __le16 TotalParameterCount;
@@ -1551,12 +1589,20 @@ typedef struct {
1551 __le16 MinorVersionNumber; 1589 __le16 MinorVersionNumber;
1552 __le64 Capability; 1590 __le64 Capability;
1553} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ 1591} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */
1592
1593/* Version numbers for CIFS UNIX major and minor. */
1594#define CIFS_UNIX_MAJOR_VERSION 1
1595#define CIFS_UNIX_MINOR_VERSION 0
1596
1554/* Linux/Unix extensions capability flags */ 1597/* Linux/Unix extensions capability flags */
1555#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ 1598#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */
1556#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ 1599#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */
1557#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ 1600#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */
1558#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ 1601#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */
1602#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Use POSIX pathnames on the wire. */
1603
1559#define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ 1604#define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */
1605
1560typedef struct { 1606typedef struct {
1561 /* For undefined recommended transfer size return -1 in that field */ 1607 /* For undefined recommended transfer size return -1 in that field */
1562 __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ 1608 __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b43ac9230eab..c7b220206ce0 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -40,7 +40,7 @@ extern unsigned int _GetXid(void);
40extern void _FreeXid(unsigned int); 40extern void _FreeXid(unsigned int);
41#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); 41#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
42#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} 42#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));}
43extern char *build_path_from_dentry(struct dentry *); 43extern char *build_path_from_dentry(struct dentry *, const struct cifs_sb_info *cifs_sb);
44extern char *build_wildcard_path_from_dentry(struct dentry *direntry); 44extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
45extern void renew_parental_timestamps(struct dentry *direntry); 45extern void renew_parental_timestamps(struct dentry *direntry);
46extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, 46extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
@@ -93,7 +93,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
93 93
94extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, 94extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
95 const char *searchName, const struct nls_table *nls_codepage, 95 const char *searchName, const struct nls_table *nls_codepage,
96 __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map); 96 __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep);
97 97
98extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, 98extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
99 __u16 searchHandle, struct cifs_search_info * psrch_inf); 99 __u16 searchHandle, struct cifs_search_info * psrch_inf);
@@ -129,6 +129,9 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
129 int remap); 129 int remap);
130extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, 130extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
131 struct kstatfs *FSData); 131 struct kstatfs *FSData);
132extern int CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
133 __u64 cap);
134
132extern int CIFSSMBQFSAttributeInfo(const int xid, 135extern int CIFSSMBQFSAttributeInfo(const int xid,
133 struct cifsTconInfo *tcon); 136 struct cifsTconInfo *tcon);
134extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); 137extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index b4f7b9859e3b..7d14f2414812 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2411,7 +2411,9 @@ findUniqueRetry:
2411 if (rc) { 2411 if (rc) {
2412 cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); 2412 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2413 } else { /* decode response */ 2413 } else { /* decode response */
2414 2414#ifdef CONFIG_CIFS_STATS
2415 atomic_inc(&tcon->num_ffirst);
2416#endif
2415 /* BB fill in */ 2417 /* BB fill in */
2416 } 2418 }
2417 2419
@@ -2429,7 +2431,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2429 const char *searchName, 2431 const char *searchName,
2430 const struct nls_table *nls_codepage, 2432 const struct nls_table *nls_codepage,
2431 __u16 * pnetfid, 2433 __u16 * pnetfid,
2432 struct cifs_search_info * psrch_inf, int remap) 2434 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2433{ 2435{
2434/* level 257 SMB_ */ 2436/* level 257 SMB_ */
2435 TRANSACTION2_FFIRST_REQ *pSMB = NULL; 2437 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -2456,7 +2458,7 @@ findFirstRetry:
2456 it got remapped to 0xF03A as if it were part of the 2458 it got remapped to 0xF03A as if it were part of the
2457 directory name instead of a wildcard */ 2459 directory name instead of a wildcard */
2458 name_len *= 2; 2460 name_len *= 2;
2459 pSMB->FileName[name_len] = '\\'; 2461 pSMB->FileName[name_len] = dirsep;
2460 pSMB->FileName[name_len+1] = 0; 2462 pSMB->FileName[name_len+1] = 0;
2461 pSMB->FileName[name_len+2] = '*'; 2463 pSMB->FileName[name_len+2] = '*';
2462 pSMB->FileName[name_len+3] = 0; 2464 pSMB->FileName[name_len+3] = 0;
@@ -2470,7 +2472,7 @@ findFirstRetry:
2470 if(name_len > buffersize-header) 2472 if(name_len > buffersize-header)
2471 free buffer exit; BB */ 2473 free buffer exit; BB */
2472 strncpy(pSMB->FileName, searchName, name_len); 2474 strncpy(pSMB->FileName, searchName, name_len);
2473 pSMB->FileName[name_len] = '\\'; 2475 pSMB->FileName[name_len] = dirsep;
2474 pSMB->FileName[name_len+1] = '*'; 2476 pSMB->FileName[name_len+1] = '*';
2475 pSMB->FileName[name_len+2] = 0; 2477 pSMB->FileName[name_len+2] = 0;
2476 name_len += 3; 2478 name_len += 3;
@@ -2524,6 +2526,9 @@ findFirstRetry:
2524 if (rc == -EAGAIN) 2526 if (rc == -EAGAIN)
2525 goto findFirstRetry; 2527 goto findFirstRetry;
2526 } else { /* decode response */ 2528 } else { /* decode response */
2529#ifdef CONFIG_CIFS_STATS
2530 atomic_inc(&tcon->num_ffirst);
2531#endif
2527 /* BB remember to free buffer if error BB */ 2532 /* BB remember to free buffer if error BB */
2528 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 2533 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2529 if(rc == 0) { 2534 if(rc == 0) {
@@ -2637,6 +2642,9 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2637 } else 2642 } else
2638 cFYI(1, ("FindNext returned = %d", rc)); 2643 cFYI(1, ("FindNext returned = %d", rc));
2639 } else { /* decode response */ 2644 } else { /* decode response */
2645#ifdef CONFIG_CIFS_STATS
2646 atomic_inc(&tcon->num_fnext);
2647#endif
2640 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 2648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2641 2649
2642 if(rc == 0) { 2650 if(rc == 0) {
@@ -2706,6 +2714,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
2706 if (rc) { 2714 if (rc) {
2707 cERROR(1, ("Send error in FindClose = %d", rc)); 2715 cERROR(1, ("Send error in FindClose = %d", rc));
2708 } 2716 }
2717#ifdef CONFIG_CIFS_STATS
2718 atomic_inc(&tcon->num_fclose);
2719#endif
2709 cifs_small_buf_release(pSMB); 2720 cifs_small_buf_release(pSMB);
2710 2721
2711 /* Since session is dead, search handle closed on server already */ 2722 /* Since session is dead, search handle closed on server already */
@@ -3269,6 +3280,77 @@ QFSUnixRetry:
3269 return rc; 3280 return rc;
3270} 3281}
3271 3282
3283int
3284CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3285{
3286/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3287 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3288 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3289 int rc = 0;
3290 int bytes_returned = 0;
3291 __u16 params, param_offset, offset, byte_count;
3292
3293 cFYI(1, ("In SETFSUnixInfo"));
3294SETFSUnixRetry:
3295 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3296 (void **) &pSMBr);
3297 if (rc)
3298 return rc;
3299
3300 params = 4; /* 2 bytes zero followed by info level. */
3301 pSMB->MaxSetupCount = 0;
3302 pSMB->Reserved = 0;
3303 pSMB->Flags = 0;
3304 pSMB->Timeout = 0;
3305 pSMB->Reserved2 = 0;
3306 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3307 offset = param_offset + params;
3308
3309 pSMB->MaxParameterCount = cpu_to_le16(4);
3310 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3311 pSMB->SetupCount = 1;
3312 pSMB->Reserved3 = 0;
3313 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3314 byte_count = 1 /* pad */ + params + 12;
3315
3316 pSMB->DataCount = cpu_to_le16(12);
3317 pSMB->ParameterCount = cpu_to_le16(params);
3318 pSMB->TotalDataCount = pSMB->DataCount;
3319 pSMB->TotalParameterCount = pSMB->ParameterCount;
3320 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3321 pSMB->DataOffset = cpu_to_le16(offset);
3322
3323 /* Params. */
3324 pSMB->FileNum = 0;
3325 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3326
3327 /* Data. */
3328 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3329 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3330 pSMB->ClientUnixCap = cpu_to_le64(cap);
3331
3332 pSMB->hdr.smb_buf_length += byte_count;
3333 pSMB->ByteCount = cpu_to_le16(byte_count);
3334
3335 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3336 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3337 if (rc) {
3338 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3339 } else { /* decode response */
3340 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3341 if (rc) {
3342 rc = -EIO; /* bad smb */
3343 }
3344 }
3345 cifs_buf_release(pSMB);
3346
3347 if (rc == -EAGAIN)
3348 goto SETFSUnixRetry;
3349
3350 return rc;
3351}
3352
3353
3272 3354
3273int 3355int
3274CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, 3356CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index e568cc47a7f9..bef5d6f30975 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -74,6 +74,7 @@ struct smb_vol {
74 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ 74 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
75 unsigned direct_io:1; 75 unsigned direct_io:1;
76 unsigned remap:1; /* set to remap seven reserved chars in filenames */ 76 unsigned remap:1; /* set to remap seven reserved chars in filenames */
77 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
77 unsigned int rsize; 78 unsigned int rsize;
78 unsigned int wsize; 79 unsigned int wsize;
79 unsigned int sockopt; 80 unsigned int sockopt;
@@ -745,6 +746,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
745 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ 746 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
746 vol->rw = TRUE; 747 vol->rw = TRUE;
747 748
749 /* default is always to request posix paths. */
750 vol->posix_paths = 1;
751
748 if (!options) 752 if (!options)
749 return 1; 753 return 1;
750 754
@@ -1023,6 +1027,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
1023 vol->remap = 1; 1027 vol->remap = 1;
1024 } else if (strnicmp(data, "nomapchars", 10) == 0) { 1028 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1025 vol->remap = 0; 1029 vol->remap = 0;
1030 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1031 vol->posix_paths = 1;
1032 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1033 vol->posix_paths = 0;
1026 } else if (strnicmp(data, "setuids", 7) == 0) { 1034 } else if (strnicmp(data, "setuids", 7) == 0) {
1027 vol->setuids = 1; 1035 vol->setuids = 1;
1028 } else if (strnicmp(data, "nosetuids", 9) == 0) { 1036 } else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -1679,6 +1687,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1679 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; 1687 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1680 if(volume_info.no_xattr) 1688 if(volume_info.no_xattr)
1681 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; 1689 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1690
1682 if(volume_info.direct_io) { 1691 if(volume_info.direct_io) {
1683 cERROR(1,("mounting share using direct i/o")); 1692 cERROR(1,("mounting share using direct i/o"));
1684 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; 1693 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
@@ -1781,6 +1790,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1781 cFYI(1,("server negotiated posix acl support")); 1790 cFYI(1,("server negotiated posix acl support"));
1782 sb->s_flags |= MS_POSIXACL; 1791 sb->s_flags |= MS_POSIXACL;
1783 } 1792 }
1793
1794 /* Try and negotiate POSIX pathnames if we can. */
1795 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1796 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1797 if (!CIFSSMBSETFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP, 0)) {
1798 cFYI(1,("negotiated posix pathnames support"));
1799 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1800 } else {
1801 cFYI(1,("posix pathnames support requested but not supported"));
1802 }
1803 }
1784 } 1804 }
1785 } 1805 }
1786 } 1806 }
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 3f3538d4a1fa..9360d8fb9ef7 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -43,7 +43,7 @@ renew_parental_timestamps(struct dentry *direntry)
43 43
44/* Note: caller must free return buffer */ 44/* Note: caller must free return buffer */
45char * 45char *
46build_path_from_dentry(struct dentry *direntry) 46build_path_from_dentry(struct dentry *direntry, const struct cifs_sb_info *cifs_sb)
47{ 47{
48 struct dentry *temp; 48 struct dentry *temp;
49 int namelen = 0; 49 int namelen = 0;
@@ -74,7 +74,7 @@ cifs_bp_rename_retry:
74 if (namelen < 0) { 74 if (namelen < 0) {
75 break; 75 break;
76 } else { 76 } else {
77 full_path[namelen] = '\\'; 77 full_path[namelen] = CIFS_DIR_SEP(cifs_sb);
78 strncpy(full_path + namelen + 1, temp->d_name.name, 78 strncpy(full_path + namelen + 1, temp->d_name.name,
79 temp->d_name.len); 79 temp->d_name.len);
80 cFYI(0, (" name: %s ", full_path + namelen)); 80 cFYI(0, (" name: %s ", full_path + namelen));
@@ -138,7 +138,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
138 pTcon = cifs_sb->tcon; 138 pTcon = cifs_sb->tcon;
139 139
140 down(&direntry->d_sb->s_vfs_rename_sem); 140 down(&direntry->d_sb->s_vfs_rename_sem);
141 full_path = build_path_from_dentry(direntry); 141 full_path = build_path_from_dentry(direntry, cifs_sb);
142 up(&direntry->d_sb->s_vfs_rename_sem); 142 up(&direntry->d_sb->s_vfs_rename_sem);
143 if(full_path == NULL) { 143 if(full_path == NULL) {
144 FreeXid(xid); 144 FreeXid(xid);
@@ -299,7 +299,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
299 pTcon = cifs_sb->tcon; 299 pTcon = cifs_sb->tcon;
300 300
301 down(&direntry->d_sb->s_vfs_rename_sem); 301 down(&direntry->d_sb->s_vfs_rename_sem);
302 full_path = build_path_from_dentry(direntry); 302 full_path = build_path_from_dentry(direntry, cifs_sb);
303 up(&direntry->d_sb->s_vfs_rename_sem); 303 up(&direntry->d_sb->s_vfs_rename_sem);
304 if(full_path == NULL) 304 if(full_path == NULL)
305 rc = -ENOMEM; 305 rc = -ENOMEM;
@@ -360,7 +360,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
360 /* can not grab the rename sem here since it would 360 /* can not grab the rename sem here since it would
361 deadlock in the cases (beginning of sys_rename itself) 361 deadlock in the cases (beginning of sys_rename itself)
362 in which we already have the sb rename sem */ 362 in which we already have the sb rename sem */
363 full_path = build_path_from_dentry(direntry); 363 full_path = build_path_from_dentry(direntry, cifs_sb);
364 if(full_path == NULL) { 364 if(full_path == NULL) {
365 FreeXid(xid); 365 FreeXid(xid);
366 return ERR_PTR(-ENOMEM); 366 return ERR_PTR(-ENOMEM);
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
index 7d2a9202c39a..d47ce7f49dc3 100644
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -83,7 +83,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
83 pTcon = cifs_sb->tcon; 83 pTcon = cifs_sb->tcon;
84 84
85 down(&file->f_dentry->d_sb->s_vfs_rename_sem); 85 down(&file->f_dentry->d_sb->s_vfs_rename_sem);
86 full_path = build_path_from_dentry(file->f_dentry); 86 full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
87 up(&file->f_dentry->d_sb->s_vfs_rename_sem); 87 up(&file->f_dentry->d_sb->s_vfs_rename_sem);
88 88
89 if(full_path == NULL) { 89 if(full_path == NULL) {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 0cec0e76d85e..f55c0c7aeeb0 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -196,7 +196,7 @@ int cifs_open(struct inode *inode, struct file *file)
196 } 196 }
197 197
198 down(&inode->i_sb->s_vfs_rename_sem); 198 down(&inode->i_sb->s_vfs_rename_sem);
199 full_path = build_path_from_dentry(file->f_dentry); 199 full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
200 up(&inode->i_sb->s_vfs_rename_sem); 200 up(&inode->i_sb->s_vfs_rename_sem);
201 if (full_path == NULL) { 201 if (full_path == NULL) {
202 FreeXid(xid); 202 FreeXid(xid);
@@ -359,7 +359,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
359 those that already have the rename sem can end up causing writepage 359 those that already have the rename sem can end up causing writepage
360 to get called and if the server was down that means we end up here, 360 to get called and if the server was down that means we end up here,
361 and we can never tell if the caller already has the rename_sem */ 361 and we can never tell if the caller already has the rename_sem */
362 full_path = build_path_from_dentry(file->f_dentry); 362 full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
363 if (full_path == NULL) { 363 if (full_path == NULL) {
364 up(&pCifsFile->fh_sem); 364 up(&pCifsFile->fh_sem);
365 FreeXid(xid); 365 FreeXid(xid);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 8d336a900255..95354da606d6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -412,7 +412,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
412 /* Unlink can be called from rename so we can not grab the sem here 412 /* Unlink can be called from rename so we can not grab the sem here
413 since we deadlock otherwise */ 413 since we deadlock otherwise */
414/* down(&direntry->d_sb->s_vfs_rename_sem);*/ 414/* down(&direntry->d_sb->s_vfs_rename_sem);*/
415 full_path = build_path_from_dentry(direntry); 415 full_path = build_path_from_dentry(direntry, cifs_sb);
416/* up(&direntry->d_sb->s_vfs_rename_sem);*/ 416/* up(&direntry->d_sb->s_vfs_rename_sem);*/
417 if (full_path == NULL) { 417 if (full_path == NULL) {
418 FreeXid(xid); 418 FreeXid(xid);
@@ -556,7 +556,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
556 pTcon = cifs_sb->tcon; 556 pTcon = cifs_sb->tcon;
557 557
558 down(&inode->i_sb->s_vfs_rename_sem); 558 down(&inode->i_sb->s_vfs_rename_sem);
559 full_path = build_path_from_dentry(direntry); 559 full_path = build_path_from_dentry(direntry, cifs_sb);
560 up(&inode->i_sb->s_vfs_rename_sem); 560 up(&inode->i_sb->s_vfs_rename_sem);
561 if (full_path == NULL) { 561 if (full_path == NULL) {
562 FreeXid(xid); 562 FreeXid(xid);
@@ -627,7 +627,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
627 pTcon = cifs_sb->tcon; 627 pTcon = cifs_sb->tcon;
628 628
629 down(&inode->i_sb->s_vfs_rename_sem); 629 down(&inode->i_sb->s_vfs_rename_sem);
630 full_path = build_path_from_dentry(direntry); 630 full_path = build_path_from_dentry(direntry, cifs_sb);
631 up(&inode->i_sb->s_vfs_rename_sem); 631 up(&inode->i_sb->s_vfs_rename_sem);
632 if (full_path == NULL) { 632 if (full_path == NULL) {
633 FreeXid(xid); 633 FreeXid(xid);
@@ -680,8 +680,8 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
680 680
681 /* we already have the rename sem so we do not need to grab it again 681 /* we already have the rename sem so we do not need to grab it again
682 here to protect the path integrity */ 682 here to protect the path integrity */
683 fromName = build_path_from_dentry(source_direntry); 683 fromName = build_path_from_dentry(source_direntry, cifs_sb_source);
684 toName = build_path_from_dentry(target_direntry); 684 toName = build_path_from_dentry(target_direntry, cifs_sb_target);
685 if ((fromName == NULL) || (toName == NULL)) { 685 if ((fromName == NULL) || (toName == NULL)) {
686 rc = -ENOMEM; 686 rc = -ENOMEM;
687 goto cifs_rename_exit; 687 goto cifs_rename_exit;
@@ -797,7 +797,7 @@ int cifs_revalidate(struct dentry *direntry)
797 797
798 /* can not safely grab the rename sem here if rename calls revalidate 798 /* can not safely grab the rename sem here if rename calls revalidate
799 since that would deadlock */ 799 since that would deadlock */
800 full_path = build_path_from_dentry(direntry); 800 full_path = build_path_from_dentry(direntry, cifs_sb);
801 if (full_path == NULL) { 801 if (full_path == NULL) {
802 FreeXid(xid); 802 FreeXid(xid);
803 return -ENOMEM; 803 return -ENOMEM;
@@ -946,7 +946,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
946 pTcon = cifs_sb->tcon; 946 pTcon = cifs_sb->tcon;
947 947
948 down(&direntry->d_sb->s_vfs_rename_sem); 948 down(&direntry->d_sb->s_vfs_rename_sem);
949 full_path = build_path_from_dentry(direntry); 949 full_path = build_path_from_dentry(direntry, cifs_sb);
950 up(&direntry->d_sb->s_vfs_rename_sem); 950 up(&direntry->d_sb->s_vfs_rename_sem);
951 if (full_path == NULL) { 951 if (full_path == NULL) {
952 FreeXid(xid); 952 FreeXid(xid);
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index bde0fabfece0..214aa816f669 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -49,8 +49,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
49 BB note DFS case in future though (when we may have to check) */ 49 BB note DFS case in future though (when we may have to check) */
50 50
51 down(&inode->i_sb->s_vfs_rename_sem); 51 down(&inode->i_sb->s_vfs_rename_sem);
52 fromName = build_path_from_dentry(old_file); 52 fromName = build_path_from_dentry(old_file, cifs_sb_target);
53 toName = build_path_from_dentry(direntry); 53 toName = build_path_from_dentry(direntry, cifs_sb_target);
54 up(&inode->i_sb->s_vfs_rename_sem); 54 up(&inode->i_sb->s_vfs_rename_sem);
55 if((fromName == NULL) || (toName == NULL)) { 55 if((fromName == NULL) || (toName == NULL)) {
56 rc = -ENOMEM; 56 rc = -ENOMEM;
@@ -105,16 +105,17 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
105 105
106 xid = GetXid(); 106 xid = GetXid();
107 107
108 cifs_sb = CIFS_SB(inode->i_sb);
109 pTcon = cifs_sb->tcon;
110
108 down(&direntry->d_sb->s_vfs_rename_sem); 111 down(&direntry->d_sb->s_vfs_rename_sem);
109 full_path = build_path_from_dentry(direntry); 112 full_path = build_path_from_dentry(direntry, cifs_sb);
110 up(&direntry->d_sb->s_vfs_rename_sem); 113 up(&direntry->d_sb->s_vfs_rename_sem);
111 114
112 if (!full_path) 115 if (!full_path)
113 goto out_no_free; 116 goto out_no_free;
114 117
115 cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); 118 cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
116 cifs_sb = CIFS_SB(inode->i_sb);
117 pTcon = cifs_sb->tcon;
118 target_path = kmalloc(PATH_MAX, GFP_KERNEL); 119 target_path = kmalloc(PATH_MAX, GFP_KERNEL);
119 if (!target_path) { 120 if (!target_path) {
120 target_path = ERR_PTR(-ENOMEM); 121 target_path = ERR_PTR(-ENOMEM);
@@ -167,7 +168,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
167 pTcon = cifs_sb->tcon; 168 pTcon = cifs_sb->tcon;
168 169
169 down(&inode->i_sb->s_vfs_rename_sem); 170 down(&inode->i_sb->s_vfs_rename_sem);
170 full_path = build_path_from_dentry(direntry); 171 full_path = build_path_from_dentry(direntry, cifs_sb);
171 up(&inode->i_sb->s_vfs_rename_sem); 172 up(&inode->i_sb->s_vfs_rename_sem);
172 173
173 if(full_path == NULL) { 174 if(full_path == NULL) {
@@ -233,7 +234,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
233/* BB would it be safe against deadlock to grab this sem 234/* BB would it be safe against deadlock to grab this sem
234 even though rename itself grabs the sem and calls lookup? */ 235 even though rename itself grabs the sem and calls lookup? */
235/* down(&inode->i_sb->s_vfs_rename_sem);*/ 236/* down(&inode->i_sb->s_vfs_rename_sem);*/
236 full_path = build_path_from_dentry(direntry); 237 full_path = build_path_from_dentry(direntry, cifs_sb);
237/* up(&inode->i_sb->s_vfs_rename_sem);*/ 238/* up(&inode->i_sb->s_vfs_rename_sem);*/
238 239
239 if(full_path == NULL) { 240 if(full_path == NULL) {
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 22557716f9af..42310281871c 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -190,8 +190,9 @@ static void fill_in_inode(struct inode *tmp_inode,
190 tmp_inode->i_data.a_ops = &cifs_addr_ops; 190 tmp_inode->i_data.a_ops = &cifs_addr_ops;
191 191
192 if(isNewInode) 192 if(isNewInode)
193 return; /* No sense invalidating pages for new inode since we 193 return; /* No sense invalidating pages for new inode
194 have not started caching readahead file data yet */ 194 since have not started caching readahead file
195 data yet */
195 196
196 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && 197 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
197 (local_size == tmp_inode->i_size)) { 198 (local_size == tmp_inode->i_size)) {
@@ -353,7 +354,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
353 return -EINVAL; 354 return -EINVAL;
354 355
355 down(&file->f_dentry->d_sb->s_vfs_rename_sem); 356 down(&file->f_dentry->d_sb->s_vfs_rename_sem);
356 full_path = build_path_from_dentry(file->f_dentry); 357 full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
357 up(&file->f_dentry->d_sb->s_vfs_rename_sem); 358 up(&file->f_dentry->d_sb->s_vfs_rename_sem);
358 359
359 if(full_path == NULL) { 360 if(full_path == NULL) {
@@ -374,7 +375,7 @@ ffirst_retry:
374 375
375 rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, 376 rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
376 &cifsFile->netfid, &cifsFile->srch_inf, 377 &cifsFile->netfid, &cifsFile->srch_inf,
377 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 378 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
378 if(rc == 0) 379 if(rc == 0)
379 cifsFile->invalidHandle = FALSE; 380 cifsFile->invalidHandle = FALSE;
380 if((rc == -EOPNOTSUPP) && 381 if((rc == -EOPNOTSUPP) &&
@@ -536,7 +537,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
536 while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 537 while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
537 (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ 538 (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
538 cFYI(1,("calling findnext2")); 539 cFYI(1,("calling findnext2"));
539 rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); 540 rc = CIFSFindNext(xid,pTcon,cifsFile->netfid,
541 &cifsFile->srch_inf);
540 if(rc) 542 if(rc)
541 return -ENOENT; 543 return -ENOENT;
542 } 544 }
@@ -555,7 +557,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
555 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 557 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
556 current_entry = cifsFile->srch_inf.srch_entries_start; 558 current_entry = cifsFile->srch_inf.srch_entries_start;
557 for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { 559 for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
558 /* go entry to next entry figuring out which we need to start with */ 560 /* go entry by entry figuring out which is first */
559 /* if( . or ..) 561 /* if( . or ..)
560 skip */ 562 skip */
561 rc = cifs_entry_is_dot(current_entry,cifsFile); 563 rc = cifs_entry_is_dot(current_entry,cifsFile);
@@ -721,7 +723,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
721 (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); 723 (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
722 } 724 }
723 725
724 rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); 726 rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
727 tmp_inode->i_ino,obj_type);
725 if(rc) { 728 if(rc) {
726 cFYI(1,("filldir rc = %d",rc)); 729 cFYI(1,("filldir rc = %d",rc));
727 } 730 }
@@ -906,7 +909,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
906 cifs_save_resume_key(current_entry,cifsFile); 909 cifs_save_resume_key(current_entry,cifsFile);
907 break; 910 break;
908 } else 911 } else
909 current_entry = nxt_dir_entry(current_entry,end_of_smb); 912 current_entry = nxt_dir_entry(current_entry,
913 end_of_smb);
910 } 914 }
911 kfree(tmp_buf); 915 kfree(tmp_buf);
912 break; 916 break;
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index c1e02eff1d25..f4fc8ddebba7 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -63,7 +63,7 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name)
63 pTcon = cifs_sb->tcon; 63 pTcon = cifs_sb->tcon;
64 64
65 down(&sb->s_vfs_rename_sem); 65 down(&sb->s_vfs_rename_sem);
66 full_path = build_path_from_dentry(direntry); 66 full_path = build_path_from_dentry(direntry, cifs_sb);
67 up(&sb->s_vfs_rename_sem); 67 up(&sb->s_vfs_rename_sem);
68 if(full_path == NULL) { 68 if(full_path == NULL) {
69 FreeXid(xid); 69 FreeXid(xid);
@@ -118,7 +118,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
118 pTcon = cifs_sb->tcon; 118 pTcon = cifs_sb->tcon;
119 119
120 down(&sb->s_vfs_rename_sem); 120 down(&sb->s_vfs_rename_sem);
121 full_path = build_path_from_dentry(direntry); 121 full_path = build_path_from_dentry(direntry, cifs_sb);
122 up(&sb->s_vfs_rename_sem); 122 up(&sb->s_vfs_rename_sem);
123 if(full_path == NULL) { 123 if(full_path == NULL) {
124 FreeXid(xid); 124 FreeXid(xid);
@@ -227,7 +227,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
227 pTcon = cifs_sb->tcon; 227 pTcon = cifs_sb->tcon;
228 228
229 down(&sb->s_vfs_rename_sem); 229 down(&sb->s_vfs_rename_sem);
230 full_path = build_path_from_dentry(direntry); 230 full_path = build_path_from_dentry(direntry, cifs_sb);
231 up(&sb->s_vfs_rename_sem); 231 up(&sb->s_vfs_rename_sem);
232 if(full_path == NULL) { 232 if(full_path == NULL) {
233 FreeXid(xid); 233 FreeXid(xid);
@@ -328,7 +328,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
328 pTcon = cifs_sb->tcon; 328 pTcon = cifs_sb->tcon;
329 329
330 down(&sb->s_vfs_rename_sem); 330 down(&sb->s_vfs_rename_sem);
331 full_path = build_path_from_dentry(direntry); 331 full_path = build_path_from_dentry(direntry, cifs_sb);
332 up(&sb->s_vfs_rename_sem); 332 up(&sb->s_vfs_rename_sem);
333 if(full_path == NULL) { 333 if(full_path == NULL) {
334 FreeXid(xid); 334 FreeXid(xid);