Windows: File Attribute Reporting Consistency
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
index e58163f..4207e10 100644 (file)
@@ -108,6 +108,38 @@ RDR_FID2fid( AFSFileID *FileId, cm_fid_t *fid)
     fid->hash = FileId->Hash;
 }
 
+unsigned long
+RDR_ExtAttributes(cm_scache_t *scp)
+{
+    unsigned long attrs;
+
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+        scp->fid.vnode & 0x1)
+    {
+        attrs = SMB_ATTR_DIRECTORY;
+#ifdef SPECIAL_FOLDERS
+        attrs |= SMB_ATTR_SYSTEM;              /* FILE_ATTRIBUTE_SYSTEM */
+#endif /* SPECIAL_FOLDERS */
+    } else if ( scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                scp->fileType == CM_SCACHETYPE_DFSLINK ||
+                scp->fileType == CM_SCACHETYPE_INVALID)
+    {
+        attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
+    } else if ( scp->fileType == CM_SCACHETYPE_SYMLINK) {
+        attrs = SMB_ATTR_REPARSE_POINT;
+    } else {
+        attrs = 0;
+    }
+
+    if ((scp->unixModeBits & 0200) == 0)
+        attrs |= SMB_ATTR_READONLY;            /* Read-only */
+
+    if (attrs == 0)
+        attrs = SMB_ATTR_NORMAL;               /* FILE_ATTRIBUTE_NORMAL */
+
+    return attrs;
+}
+
 DWORD
 RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRedirInitInfoLen )
 {
@@ -508,6 +540,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
             break;
         case CM_SCACHETYPE_MOUNTPOINT:
         case CM_SCACHETYPE_INVALID:
+        case CM_SCACHETYPE_DFSLINK:
             pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
             break;
         case CM_SCACHETYPE_SYMLINK:
@@ -530,7 +563,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                 pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
         }
     } else
-        pCurrentEntry->FileAttributes = smb_ExtAttributes(scp);
+        pCurrentEntry->FileAttributes = RDR_ExtAttributes(scp);
     pCurrentEntry->EaSize = 0;
     pCurrentEntry->Links = scp->linkCount;
 
@@ -606,38 +639,110 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
             wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
 
             if (dwFlags & RDR_POP_EVALUATE_SYMLINKS) {
-                char * mp;
 
                 code2 = cm_HandleLink(scp, userp, reqp);
                 if (code2 == 0) {
-                    mp = scp->mountPointStringp;
-                    len = strlen(mp);
-                    if ( len != 0 ) {
-                        /* Strip off the msdfs: prefix from the target name for the file system */
-                        if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
-                            osi_Log0(afsd_logp, "RDR_PopulateCurrentEntry DFSLink Detected");
-                            pCurrentEntry->FileType = scp->fileType;
-
-                            if (!strncmp("msdfs:", mp, 6)) {
-                                mp += 6;
-                                len -= 6;
-                            }
+                    size_t wtarget_len = 0;
+
+                    if (scp->mountPointStringp[0]) {
+                        char * mp;
+                        char * s;
+                        size_t offset = 0;
+
+                        len = strlen(scp->mountPointStringp) + 1;
+                        mp = strdup(scp->mountPointStringp);
+
+                        for (s=mp; *s; s++) {
+                            if (*s == '/')
+                                *s = '\\';
                         }
-                        /* only send one slash to the redirector */
-                        if (mp[0] == '\\' && mp[1] == '\\') {
-                            mp++;
-                            len--;
+
+                        if (strncmp("msdfs:", mp, 6) == 0) {
+                            offset = 6;
                         }
+
+
+                        if ( mp[offset + 1] == ':' && mp[offset] != '\\') {
+                            /* Local drive letter.  Must return <drive>:\<path> */
+                            pCurrentEntry->FileType = CM_SCACHETYPE_DFSLINK;
+                            wtarget_len = len - offset;
 #ifdef UNICODE
-                        cch = MultiByteToWideChar( CP_UTF8, 0, mp,
-                                                   len * sizeof(char),
-                                                   wtarget,
-                                                   len * sizeof(WCHAR));
+                            cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+                                                       wtarget_len * sizeof(char),
+                                                       wtarget,
+                                                       wtarget_len * sizeof(WCHAR));
 #else
-                        mbstowcs(wtarget, mp, len);
+                            mbstowcs(wtarget, &mp[offset], wtarget_len);
 #endif
+                        } else if (mp[offset] == '\\') {
+                            size_t nbNameLen = strlen(cm_NetbiosName);
+
+                            if ( strnicmp(&mp[offset + 1], cm_NetbiosName, nbNameLen) == 0 &&
+                                 mp[offset + nbNameLen + 1] == '\\')
+                            {
+                                /* an AFS symlink */
+                                pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+                                wtarget_len = len - offset;
+#ifdef UNICODE
+                                cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+                                                           wtarget_len * sizeof(char),
+                                                           wtarget,
+                                                           wtarget_len * sizeof(WCHAR));
+#else
+                                mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+                            } else if ( mp[offset + 1] == '\\' &&
+                                        strnicmp(&mp[offset + 2], cm_NetbiosName, strlen(cm_NetbiosName)) == 0 &&
+                                        mp[offset + nbNameLen + 2] == '\\')
+                            {
+                                /* an AFS symlink */
+                                pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+                                wtarget_len = len - offset - 1;
+#ifdef UNICODE
+                                cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset + 1],
+                                                           wtarget_len * sizeof(char),
+                                                           wtarget,
+                                                           wtarget_len * sizeof(WCHAR));
+#else
+                                mbstowcs(wtarget, &mp[offset + 1], wtarget_len);
+#endif
+                            } else {
+                                /*
+                                 * treat as a UNC path. Needs to be \<server>\<share\<path>
+                                 */
+                                pCurrentEntry->FileType = CM_SCACHETYPE_DFSLINK;
+
+                                if ( mp[offset] == '\\' && mp[offset + 1] == '\\')
+                                     offset++;
+
+                                wtarget_len = len - offset;
+#ifdef UNICODE
+                                cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+                                                           wtarget_len * sizeof(char),
+                                                           wtarget,
+                                                           wtarget_len * sizeof(WCHAR));
+#else
+                                mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+                            }
+                        } else {
+                            /* Relative AFS Symlink */
+                            pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+                            wtarget_len = len - offset;
+#ifdef UNICODE
+                            cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+                                                       wtarget_len * sizeof(char),
+                                                       wtarget,
+                                                       wtarget_len * sizeof(WCHAR));
+#else
+                            mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+                        }
+
+                        free(mp);
                     }
-                    pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
+
+                    pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * (wtarget_len - 1));
                 } else {
                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_HandleLink failed scp=0x%p code=0x%x",
                              scp, code2);
@@ -718,8 +823,6 @@ RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
     pCurrentEntry->FileId.Unique = fidp->unique;
     pCurrentEntry->FileId.Hash = fidp->hash;
 
-    pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
-
     pCurrentEntry->DataVersion.QuadPart = CM_SCACHE_VERSION_BAD;
 
     cm_LargeSearchTimeFromUnixTime(&ft, 0);
@@ -735,8 +838,14 @@ RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
 
     pCurrentEntry->EndOfFile.QuadPart = 0;
     pCurrentEntry->AllocationSize.QuadPart = 0;
-    pCurrentEntry->FileAttributes = 0;
+    if (fidp->vnode & 0x1) {
+        pCurrentEntry->FileType = CM_SCACHETYPE_DIRECTORY;
+        pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
+    } else {
+        pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
+        pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
     pCurrentEntry->EaSize = 0;
+    }
     pCurrentEntry->Links = 0;
 
     len = wcslen(shortName);
@@ -5690,6 +5799,7 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     cm_req_t    req;
     DWORD       status;
     FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
+    afs_uint32  flags;
 
     char volName[32]="(unknown)";
     char offLineMsg[256]="server temporarily inaccessible";
@@ -5761,7 +5871,8 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
 
         pResultCB->AvailableAllocationUnits.QuadPart = 0;
-        pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
+        if (cm_volumeInfoReadOnlyFlag)
+            pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
 
         pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( "Freelance.Local.Root", -1, pResultCB->VolumeLabel,
                                                        (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
@@ -5773,8 +5884,6 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         if ( pResultCB->CellLength )
             pResultCB->CellLength--;
     } else {
-        memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
-
         volp = cm_GetVolumeByFID(&scp->fid);
         if (!volp) {
             code = CM_ERROR_NOSUCHVOLUME;
@@ -5782,11 +5891,13 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         }
         volType = cm_VolumeType(volp, scp->fid.volume);
 
-        if (volType == ROVOL || volType == BACKVOL)
+        if (cm_volumeInfoReadOnlyFlag && (volType == ROVOL || volType == BACKVOL))
             pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
 
-        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
-                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        flags = CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS;
+        if (scp->volumeCreationDate == 0)
+            flags |= CM_SCACHESYNC_FORCECB;
+        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, flags);
         if (code == 0)
         {
             sync_done = 1;
@@ -5810,6 +5921,10 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
             code = cm_MapRPCError(code, &req);
         }
 
+        if ( scp->volumeCreationDate )
+            cm_LargeSearchTimeFromUnixTime(&ft, scp->volumeCreationDate);
+        memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
+
         if (code == 0) {
             if (volType == ROVOL || volType == BACKVOL) {
                 pResultCB->TotalAllocationUnits.QuadPart = volStat.BlocksInUse;