Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / fs / cifs / connect.c
index 5d394c7..4093d53 100644 (file)
@@ -89,6 +89,7 @@ struct smb_vol {
        unsigned int wsize;
        unsigned int sockopt;
        unsigned short int port;
+       char * prepath;
 };
 
 static int ipv4_connect(struct sockaddr_in *psin_server, 
@@ -108,7 +109,7 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server,
         * wake up waiters on reconnection? - (not needed currently)
         */
 
-int
+static int
 cifs_reconnect(struct TCP_Server_Info *server)
 {
        int rc = 0;
@@ -770,13 +771,18 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
        separator[0] = ',';
        separator[1] = 0; 
 
-       memset(vol->source_rfc1001_name,0x20,15);
-       for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
-               /* does not have to be a perfect mapping since the field is
-               informational, only used for servers that do not support
-               port 445 and it can be overridden at mount time */
-               vol->source_rfc1001_name[i] = 
-                       toupper(system_utsname.nodename[i]);
+       if (Local_System_Name[0] != 0)
+               memcpy(vol->source_rfc1001_name, Local_System_Name,15);
+       else {
+               char *nodename = utsname()->nodename;
+               int n = strnlen(nodename,15);
+               memset(vol->source_rfc1001_name,0x20,15);
+               for(i=0 ; i < n ; i++) {
+                       /* does not have to be perfect mapping since field is
+                       informational, only used for servers that do not support
+                       port 445 and it can be overridden at mount time */
+                       vol->source_rfc1001_name[i] = toupper(nodename[i]);
+               }
        }
        vol->source_rfc1001_name[15] = 0;
        /* null target name indicates to use *SMBSERVR default called name
@@ -993,6 +999,28 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                printk(KERN_WARNING "CIFS: domain name too long\n");
                                return 1;
                        }
+                } else if (strnicmp(data, "prefixpath", 10) == 0) {
+                        if (!value || !*value) {
+                                printk(KERN_WARNING
+                                       "CIFS: invalid path prefix\n");
+                                return 1;       /* needs_arg; */
+                        }
+                        if ((temp_len = strnlen(value, 1024)) < 1024) {
+                               if(value[0] != '/')
+                                       temp_len++;  /* missing leading slash */
+                                vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
+                                if(vol->prepath == NULL)
+                                        return 1;
+                               if(value[0] != '/') {
+                                       vol->prepath[0] = '/';
+                                       strcpy(vol->prepath+1,value);
+                               } else
+                                       strcpy(vol->prepath,value);
+                               cFYI(1,("prefix path %s",vol->prepath));
+                        } else {
+                                printk(KERN_WARNING "CIFS: prefix too long\n");
+                                return 1;
+                        }
                } else if (strnicmp(data, "iocharset", 9) == 0) {
                        if (!value || !*value) {
                                printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
@@ -1605,6 +1633,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
                kfree(volume_info.UNC);
                kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        }
@@ -1619,6 +1648,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
            locations such as env variables and files on disk */
                kfree(volume_info.UNC);
                kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        }
@@ -1639,6 +1669,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        /* we failed translating address */
                        kfree(volume_info.UNC);
                        kfree(volume_info.password);
+                       kfree(volume_info.prepath);
                        FreeXid(xid);
                        return -EINVAL;
                }
@@ -1651,6 +1682,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                cERROR(1,("Connecting to DFS root not implemented yet"));
                kfree(volume_info.UNC);
                kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        } else /* which servers DFS root would we conect to */ {
@@ -1658,6 +1690,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                       ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
                kfree(volume_info.UNC);
                kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        }
@@ -1672,6 +1705,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
                        kfree(volume_info.UNC);
                        kfree(volume_info.password);
+                       kfree(volume_info.prepath);
                        FreeXid(xid);
                        return -ELIBACC;
                }
@@ -1688,6 +1722,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        else {
                kfree(volume_info.UNC);
                kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        }
@@ -1710,6 +1745,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                sock_release(csocket);
                        kfree(volume_info.UNC);
                        kfree(volume_info.password);
+                       kfree(volume_info.prepath);
                        FreeXid(xid);
                        return rc;
                }
@@ -1720,6 +1756,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        sock_release(csocket);
                        kfree(volume_info.UNC);
                        kfree(volume_info.password);
+                       kfree(volume_info.prepath);
                        FreeXid(xid);
                        return rc;
                } else {
@@ -1744,6 +1781,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                sock_release(csocket);
                                kfree(volume_info.UNC);
                                kfree(volume_info.password);
+                               kfree(volume_info.prepath);
                                FreeXid(xid);
                                return rc;
                        }
@@ -1831,6 +1869,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        /* Windows ME may prefer this */
                        cFYI(1,("readsize set to minimum 2048"));
                }
+               /* calculate prepath */
+               cifs_sb->prepath = volume_info.prepath;
+               if(cifs_sb->prepath) {
+                       cifs_sb->prepathlen = strlen(cifs_sb->prepath);
+                       cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
+                       volume_info.prepath = NULL;
+               } else 
+                       cifs_sb->prepathlen = 0;
                cifs_sb->mnt_uid = volume_info.linux_uid;
                cifs_sb->mnt_gid = volume_info.linux_gid;
                cifs_sb->mnt_file_mode = volume_info.file_mode;
@@ -2008,6 +2054,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        the password ptr is put in the new session structure (in which case the
        password will be freed at unmount time) */
        kfree(volume_info.UNC);
+       kfree(volume_info.prepath);
        FreeXid(xid);
        return rc;
 }
@@ -2111,7 +2158,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
+                   cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;
@@ -2138,8 +2185,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                }
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, system_utsname.release);
-               bcc_ptr += strlen(system_utsname.release) + 1;
+               strcpy(bcc_ptr, utsname()->release);
+               bcc_ptr += strlen(utsname()->release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
        }
@@ -2403,7 +2450,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
+                   cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
                                  nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;   /* null terminate Linux version */
@@ -2420,8 +2467,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        } else {                /* ASCII */
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, system_utsname.release);
-               bcc_ptr += strlen(system_utsname.release) + 1;
+               strcpy(bcc_ptr, utsname()->release);
+               bcc_ptr += strlen(utsname()->release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
                bcc_ptr++;      /* empty domain field */
@@ -2794,7 +2841,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
+                   cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
                                  nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;   /* null term version string */
@@ -2846,8 +2893,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, system_utsname.release);
-               bcc_ptr += strlen(system_utsname.release) + 1;
+               strcpy(bcc_ptr, utsname()->release);
+               bcc_ptr += strlen(utsname()->release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
                bcc_ptr++;      /* null domain */
@@ -3173,7 +3220,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                        }
                        /* else do not bother copying these informational fields */
                }
-               if(smb_buffer_response->WordCount == 3)
+               if((smb_buffer_response->WordCount == 3) ||
+                        (smb_buffer_response->WordCount == 7))
+                       /* field is in same location */
                        tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
                else
                        tcon->Flags = 0;
@@ -3195,6 +3244,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        int xid;
        struct cifsSesInfo *ses = NULL;
        struct task_struct *cifsd_task;
+       char * tmp;
 
        xid = GetXid();
 
@@ -3228,6 +3278,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        }
        
        cifs_sb->tcon = NULL;
+       tmp = cifs_sb->prepath;
+       cifs_sb->prepathlen = 0;
+       cifs_sb->prepath = NULL;
+       kfree(tmp);
        if (ses)
                schedule_timeout_interruptible(msecs_to_jiffies(500));
        if (ses)
@@ -3265,19 +3319,21 @@ 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);
        /*      pSesInfo->sequence_number = 0;*/
-               cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
+               cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
-                       pSesInfo->server->timeZone));
+                       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->capabilities 
+                                       & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
                        rc = -EOPNOTSUPP;
                } else if (extended_security
@@ -3291,7 +3347,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        if (!rc) {
                                if(ntlmv2_flag) {
                                        char * v2_response;
-                                       cFYI(1,("Can use more secure NTLM version 2 password hash"));
+                                       cFYI(1,("more secure NTLM ver2 hash"));
                                        if(CalcNTLMv2_partial_mac_key(pSesInfo, 
                                                nls_info)) {
                                                rc = -ENOMEM;