dns-and-server-ref-counts-20040530
[openafs.git] / src / WINNT / afsd / cm_ioctl.c
index 51ba32c..187b9cf 100644 (file)
 #include "afsd_init.h"
 
 #include "smb.h"
+#include "cm_server.h"
 
 #ifndef DJGPP
-#include <rxkad.h>
+#include <rx/rxkad.h>
 #include "afsrpc.h"
 #else
 #include <rx/rxkad.h>
 
 #include "cm_rpc.h"
 
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
 /* Copied from afs_tokens.h */
 #define PIOCTL_LOGON   0x1
 #define MAX_PATH 260
 
 osi_mutex_t cm_Afsdsbmt_Lock;
-#ifdef AFS_FREELANCE_CLIENT
-extern osi_mutex_t cm_Freelance_Lock;
-#endif
 
 extern afs_int32 cryptall;
 
@@ -112,16 +114,18 @@ void cm_ResetACLCache(cm_user_t *userp)
  */
 void TranslateExtendedChars(char *str)
 {
-  char *p;
-  
-        if (!str || !*str)
-                return;
+#ifdef DJGPP
+    char *p;
+#endif
+
+    if (!str || !*str)
+        return;
 
 #ifndef DJGPP
-        CharToOem(str, str);
+    CharToOem(str, str);
 #else
-        p = str;
-        while (*p) *p++ &= 0x7f;  /* turn off high bit; probably not right */
+    p = str;
+    while (*p) *p++ &= 0x7f;  /* turn off high bit; probably not right */
 #endif
 }
         
@@ -176,15 +180,19 @@ void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
 void cm_NormalizeAfsPath (char *outpathp, char *inpathp)
 {
        char *cp;
-
-       if (!strnicmp (inpathp, "/afs", strlen("/afs")))
+    char bslash_mountRoot[256];
+       
+    strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
+    bslash_mountRoot[0] = '\\';
+       
+    if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
                lstrcpy (outpathp, inpathp);
-       else if (!strnicmp (inpathp, "\\afs", strlen("\\afs")))
+       else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
                lstrcpy (outpathp, inpathp);
        else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
-               sprintf (outpathp, "/afs%s", inpathp);
+               sprintf (outpathp, "%s%s", cm_mountRoot, inpathp);
        else // inpathp looks like "<cell>/usr"
-               sprintf (outpathp, "/afs/%s", inpathp);
+               sprintf (outpathp, "%s/%s", cm_mountRoot, inpathp);
 
        for (cp = outpathp; *cp != 0; ++cp) {
                if (*cp == '\\')
@@ -195,8 +203,8 @@ void cm_NormalizeAfsPath (char *outpathp, char *inpathp)
            outpathp[strlen(outpathp)-1] = 0;
        }
 
-       if (!strcmpi (outpathp, "/afs")) {
-           strcpy (outpathp, "/afs/");
+       if (!strcmpi (outpathp, cm_mountRoot)) {
+        strcpy (outpathp, cm_mountRoot);
        }
 }
 
@@ -918,12 +926,72 @@ long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
        else return CM_ERROR_NOMORETOKENS;      /* mapped to EDOM */
 }
 
+extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
+
 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
 {
-       /* don't need to do, since NT cache manager will re-read afsdcell.ini
-         * on every access to a new cell.
-         */
-       return CM_ERROR_INVAL;
+    /* NT cache manager will read cell information from afsdcell.ini each time
+     * cell is accessed. So, this call is necessary only if list of server for a cell 
+     * changes (or IP addresses of cell servers changes).
+     * All that needs to be done is to refresh server information for all cells that 
+     * are already loaded.
+  
+     * cell list will be cm_CellLock and cm_ServerLock will be held for write.
+    */  
+  
+    cm_cell_t *cp;
+    cm_cell_t *tcp;
+  
+    cm_SkipIoctlPath(ioctlp);
+    lock_ObtainWrite(&cm_cellLock);
+  
+    for(cp = cm_allCellsp; cp; cp=cp->nextp) 
+    {
+        long code;
+      top:
+        /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
+        cm_FreeServerList(&cp->vlServersp);
+        cp->vlServersp = NULL;
+        code = cm_SearchCellFile(cp->namep, cp->namep, cm_AddCellProc, cp);
+               if (code) {
+#ifdef AFS_AFSDB_ENV
+            if (cm_dnsEnabled) {
+                int ttl;
+                code = cm_SearchCellByDNS(cp->namep, cp->namep, &ttl, cm_AddCellProc, cp);
+                if ( code ) {
+                    if ( cm_allCellsp == cp )
+                        cm_allCellsp = cp->nextp;
+                    else {
+                        for(tcp = cm_allCellsp; tcp->nextp; tcp=tcp->nextp) {
+                            if ( tcp->nextp == cp ) {
+                                tcp->nextp = cp->nextp;
+                                break;
+                            }
+                        }
+                    }   
+                    
+                    lock_FinalizeMutex(&cp->mx);
+                    free(cp->namep);
+                }
+                else {   /* got cell from DNS */
+                    cp->flags |= CM_CELLFLAG_DNS;
+                    cp->timeout = time(0) + ttl;
+                }
+            }
+#endif /* AFS_AFSDB_ENV */
+        }
+        if (code) {
+            tcp = cp;
+            cp = cp->nextp;
+            free(tcp);
+            goto top;
+        }
+        else
+            cm_RandomizeServer(&cp->vlServersp);
+    }
+    
+    lock_ReleaseWrite(&cm_cellLock);
+    return 0;       
 }
 
 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
@@ -1030,7 +1098,8 @@ long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
        vlonly     = spin->flags;
        if ( vlonly )
                type = CM_SERVER_VLDB;
-       else    type = CM_SERVER_FILE;
+       else    
+        type = CM_SERVER_FILE;
 
        for ( i=0; i < noServers; i++) 
        {
@@ -1040,7 +1109,7 @@ long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
                tmp.sin_family = AF_INET;
 
                tsp = cm_FindServer(&tmp, type);
-               if ( tsp )              /* an existing server */
+               if ( tsp )              /* an existing server - ref count increased */
                {
                        tsp->ipRank = rank; /* no need to protect by mutex*/
 
@@ -1056,13 +1125,13 @@ long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
                            /* set preferences for an existing vlserver */
                            cm_ChangeRankCellVLServer(tsp);
                        }
+            cm_PutServer(tsp);  /* decrease refcount */
                }
-               else                    /* add a new server without a cell*/
+               else    /* add a new server without a cell */
                {
-                       tsp = cm_NewServer(&tmp, type, NULL);
+                       tsp = cm_NewServer(&tmp, type, NULL); /* refcount = 1 */
                        tsp->ipRank = rank;
                }
-               cm_PutServer(tsp);
        }
        return 0;
 }
@@ -1124,53 +1193,53 @@ long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
 {
        char leaf[256];
-        long code;
-        cm_scache_t *dscp;
-        cm_attr_t tattr;
-        char *cp;
+    long code;
+    cm_scache_t *dscp;
+    cm_attr_t tattr;
+    char *cp;
        cm_req_t req;
-        char mpInfo[256];
-        char fullCell[256];
+    char mpInfo[256];
+    char fullCell[256];
        char volume[256];
        char cell[256];
        int ttl;
 
        cm_InitReq(&req);
         
-        code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
-        if (code) return code;
+    code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
+    if (code) return code;
 
-        /* Translate chars for the mount point name */
-        TranslateExtendedChars(leaf);
+    /* Translate chars for the mount point name */
+    TranslateExtendedChars(leaf);
 
-        /* 
-         * The fs command allows the user to specify partial cell names on NT.  These must
-         * be expanded to the full cell name for mount points so that the mount points will
-         * work on UNIX clients.
-         */
+    /* 
+     * The fs command allows the user to specify partial cell names on NT.  These must
+     * be expanded to the full cell name for mount points so that the mount points will
+     * work on UNIX clients.
+     */
 
        /* Extract the possibly partial cell name */
        strcpy(cell, ioctlp->inDatap + 1);      /* Skip the mp type character */
         
-        if (cp = strchr(cell, ':')) {
+    if (cp = strchr(cell, ':')) {
                /* Extract the volume name */
-               *cp = 0;
+        *cp = 0;
                strcpy(volume,  cp + 1);
        
-               /* Get the full name for this cell */
-               code = cm_SearchCellFile(cell, fullCell, 0, 0);
+        /* Get the full name for this cell */
+        code = cm_SearchCellFile(cell, fullCell, 0, 0);
 #ifdef AFS_AFSDB_ENV
                if (code && cm_dnsEnabled)
-                  code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
+            code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
 #endif
-                 if (code)
+        if (code)
                        return CM_ERROR_NOSUCHCELL;
        
-               sprintf(mpInfo, "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
+        sprintf(mpInfo, "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
        } else {
-               /* No cell name specified */
-               strcpy(mpInfo, ioctlp->inDatap);
-        }
+        /* No cell name specified */
+        strcpy(mpInfo, ioctlp->inDatap);
+    }
 
 #ifdef AFS_FREELANCE_CLIENT
        if (cm_freelanceEnabled && dscp == cm_rootSCachep) {
@@ -1181,21 +1250,20 @@ long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
        }
 #endif
        /* create the symlink with mode 644.  The lack of X bits tells
-         * us that it is a mount point.
-         */
+     * us that it is a mount point.
+     */
        tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
-        tattr.unixModeBits = 0644;
+    tattr.unixModeBits = 0644;
        tattr.clientModTime = time(NULL);
 
-        code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
+    code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
        if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                smb_NotifyChange(FILE_ACTION_ADDED,
-                                FILE_NOTIFY_CHANGE_DIR_NAME,
-                                dscp, leaf, NULL, TRUE);
-
-        cm_ReleaseSCache(dscp);
+                         FILE_NOTIFY_CHANGE_DIR_NAME,
+                         dscp, leaf, NULL, TRUE);
 
-        return code;
+    cm_ReleaseSCache(dscp);
+    return code;
 }
 
 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
@@ -1272,7 +1340,8 @@ long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
        if (code == 0) {
                cp = ioctlp->outDatap;
                if (newRootScp != NULL) {
-                       strcpy(cp, "/afs/");
+            strcpy(cp, cm_mountRoot);
+            strcat(cp, "/");
                        cp += strlen(cp);
                }
                strcpy(cp, spacep->data);
@@ -1286,6 +1355,33 @@ long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
        return code;
 }
 
+long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{/*CHECK FOR VALID SYMLINK*/
+       long code;
+       cm_scache_t *dscp;
+       cm_scache_t *scp;
+       char *cp;
+       cm_req_t req;
+
+       cm_InitReq(&req);
+
+       code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
+       if (code) return code;
+
+       cp = ioctlp->inDatap;
+       osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
+
+       code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
+       cm_ReleaseSCache(dscp);
+       if (code) return code;
+
+       /* Check that it's a real symlink */
+       if (scp->fileType != CM_SCACHETYPE_SYMLINK)
+               code = CM_ERROR_INVAL;
+       cm_ReleaseSCache(scp);
+       return code;
+}
+
 long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
 {
        long code;
@@ -1736,8 +1832,8 @@ long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
                         */
                        WritePrivateProfileString("AFS Submounts",
                                        submountreqp, 
-                                       (strlen(&afspath[strlen("/afs")])) ?
-                                                 &afspath[strlen("/afs")]:"/",
+                                       (strlen(&afspath[strlen(cm_mountRoot)])) ?
+                                                 &afspath[strlen(cm_mountRoot)]:"/",
                                        "afsdsbmt.ini");
 
                        strcpy(ioctlp->outDatap, submountreqp);
@@ -1850,8 +1946,9 @@ long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
        sprintf(ioctlp->outDatap, "auto%ld", nextAutoSubmount);
 
        WritePrivateProfileString("AFS Submounts", ioctlp->outDatap,
-                                       &afspath[lstrlen("/afs")],
-                                       "afsdsbmt.ini");
+                                 (strlen(&afspath[lstrlen(cm_mountRoot)])) ? 
+                                 &afspath[lstrlen(cm_mountRoot)]:"/",
+                                 "afsdsbmt.ini");
 
        ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
        lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
@@ -1897,3 +1994,78 @@ long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
   return 0;
 }
 
+/* 
+ * functions to dump contents of various structures. 
+ * In debug build (linked with crt debug library) will dump allocated but not freed memory
+ */
+extern int cm_DumpSCache(FILE *outputFile, char *cookie);
+extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie);
+extern int smb_DumpVCP(FILE *outputFile, char *cookie);
+
+long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
+{
+    long inValue = 0;
+    HANDLE hLogFile;
+    char logfileName[MAX_PATH+1];
+    char *cookie;
+  
+#ifdef _DEBUG  
+    static _CrtMemState memstate;
+#endif
+  
+    cm_SkipIoctlPath(ioctlp);
+    memcpy(&inValue, ioctlp->inDatap, sizeof(long));
+  
+    if (getenv("TEMP"))
+    {
+        strncpy(logfileName, getenv("TEMP"), MAX_PATH);
+        logfileName[MAX_PATH] = '\0';
+    }
+    else
+    {
+        GetWindowsDirectory(logfileName, sizeof(logfileName));
+    }
+    strncat(logfileName, "\\afsd_alloc.log", sizeof(logfileName));
+
+    hLogFile = CreateFile(logfileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+  
+    if (!hLogFile)
+    {
+      /* error */
+      inValue = -1;
+      memcpy(ioctlp->outDatap, &inValue, sizeof(long));
+      ioctlp->outDatap += sizeof(long);
+      
+      return 0;               
+    }
+  
+    SetFilePointer(hLogFile, 0, NULL, FILE_END);
+  
+    cookie = inValue ? "b" : "e";
+  
+#ifdef _DEBUG  
+  
+    if (inValue)
+    {
+      _CrtMemCheckpoint(&memstate);           
+    }
+    else
+    {
+        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+        _CrtSetReportFile(_CRT_WARN, hLogFile);
+        _CrtMemDumpAllObjectsSince(&memstate);
+    }
+#endif
+  
+    /* dump all interesting data */
+    cm_DumpSCache(hLogFile, cookie);
+    cm_DumpBufHashTable(hLogFile, cookie);
+    smb_DumpVCP(hLogFile, cookie);
+
+    CloseHandle(hLogFile);                          
+  
+    memcpy(ioctlp->outDatap, &inValue, sizeof(long));
+    ioctlp->outDatap += sizeof(long);
+  
+    return 0;
+}