Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

456 lines
13 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name :
  4. dirlist.cxx
  5. Abstract:
  6. Handle directory listing
  7. Author:
  8. Anil Ruia (AnilR) 8-Mar-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. #include "staticfile.hxx"
  16. #define PAD_LONG_DATE 29
  17. #define PAD_SHORT_DATE 10
  18. #define PAD_TIME 8
  19. #define PAD_FILESIZE 12
  20. #define PAD_COL_SPACING 1
  21. void PadDirField(CHAR *pszString,
  22. int pad)
  23. {
  24. int cchLen = (DWORD)strlen(pszString);
  25. if (cchLen > pad)
  26. pad = cchLen;
  27. int diff = pad - cchLen;
  28. //
  29. // Insert spaces in front of the text to pad it out
  30. //
  31. memmove(pszString + diff, pszString, cchLen + 1);
  32. for (int i = 0; i < diff; i++, pszString++)
  33. *pszString = ' ';
  34. //
  35. // Append a column spacer at the end
  36. //
  37. pszString += cchLen;
  38. for (i = 0; i < PAD_COL_SPACING; i++, pszString++)
  39. *pszString = ' ';
  40. *pszString = '\0';
  41. }
  42. HRESULT AddFileEntry(IN STRA &strURL,
  43. IN WIN32_FIND_DATA *pFileData,
  44. IN DWORD dwDirBrowseFlags,
  45. IN OUT STRA *pstrResponse)
  46. /*++
  47. Routine Description:
  48. Adds the HTML corresponding to an individual directory entry to
  49. strResponse
  50. Arguments:
  51. strURL - The URL being requested
  52. pFileData - the File Information obtained from Find[First|Next]File
  53. dwDirBrowseFlags - Flags controlling how the dirlisting is formatted
  54. pstrResponse - The string where the response is assembled
  55. Returns:
  56. HRESULT
  57. --*/
  58. {
  59. HRESULT hr;
  60. //
  61. // Add optional date and time of this file. We use the locale
  62. // and timezone of the server
  63. //
  64. FILETIME lastModTime = pFileData->ftLastWriteTime;
  65. if ((dwDirBrowseFlags & (DIRBROW_SHOW_DATE | DIRBROW_SHOW_TIME)) &&
  66. ((lastModTime.dwLowDateTime != 0) ||
  67. (lastModTime.dwHighDateTime != 0)))
  68. {
  69. FILETIME ftLocal;
  70. SYSTEMTIME systime;
  71. if (!FileTimeToLocalFileTime(&lastModTime, &ftLocal) ||
  72. !FileTimeToSystemTime(&ftLocal, &systime))
  73. {
  74. return HRESULT_FROM_WIN32(GetLastError());
  75. }
  76. LCID lcid = GetSystemDefaultLCID();
  77. if (lcid == 0)
  78. {
  79. return HRESULT_FROM_WIN32(GetLastError());
  80. }
  81. if (dwDirBrowseFlags & DIRBROW_SHOW_DATE)
  82. {
  83. WCHAR pszDate[50];
  84. BOOL fLongDate = dwDirBrowseFlags & DIRBROW_LONG_DATE;
  85. if (GetDateFormatW(lcid,
  86. LOCALE_NOUSEROVERRIDE |
  87. (fLongDate ? DATE_LONGDATE :
  88. DATE_SHORTDATE),
  89. &systime,
  90. NULL,
  91. pszDate,
  92. sizeof(pszDate)/sizeof(WCHAR)) == 0)
  93. {
  94. return HRESULT_FROM_WIN32(GetLastError());
  95. }
  96. STACK_STRA (straFileDate, 50);
  97. if (FAILED(hr = straFileDate.CopyWToUTF8Unescaped(pszDate)))
  98. {
  99. return hr;
  100. }
  101. PadDirField(straFileDate.QueryStr(),
  102. fLongDate ? PAD_LONG_DATE : PAD_SHORT_DATE );
  103. DBG_REQUIRE(TRUE == straFileDate.SetLen((DWORD)strlen(straFileDate.QueryStr())));
  104. if (FAILED(hr = pstrResponse->Append(straFileDate)))
  105. {
  106. return hr;
  107. }
  108. }
  109. if (dwDirBrowseFlags & DIRBROW_SHOW_TIME)
  110. {
  111. WCHAR pszTime[15];
  112. if (GetTimeFormatW(lcid,
  113. LOCALE_NOUSEROVERRIDE |
  114. TIME_NOSECONDS,
  115. &systime,
  116. NULL,
  117. pszTime,
  118. sizeof(pszTime)/sizeof(WCHAR)) == 0)
  119. {
  120. return HRESULT_FROM_WIN32(GetLastError());
  121. }
  122. STACK_STRA (straFileTime, 15);
  123. if (FAILED(hr = straFileTime.CopyWToUTF8Unescaped(pszTime)))
  124. {
  125. return hr;
  126. }
  127. PadDirField(straFileTime.QueryStr(), PAD_TIME);
  128. DBG_REQUIRE(TRUE == straFileTime.SetLen((DWORD)strlen(straFileTime.QueryStr())));
  129. if (FAILED(hr = pstrResponse->Append(straFileTime)))
  130. {
  131. return hr;
  132. }
  133. }
  134. }
  135. //
  136. // Add the optional file size
  137. //
  138. LARGE_INTEGER liSize;
  139. liSize.HighPart = pFileData->nFileSizeHigh;
  140. liSize.LowPart = pFileData->nFileSizeLow;
  141. if (dwDirBrowseFlags & DIRBROW_SHOW_SIZE)
  142. {
  143. CHAR pszSize[30];
  144. int pad = PAD_FILESIZE;
  145. if (pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  146. {
  147. strcpy(pszSize, "&lt;dir&gt;");
  148. //
  149. // Need to adjust for using "&lt;" instead of "<"
  150. //
  151. pad += 6;
  152. }
  153. else
  154. {
  155. _i64toa(liSize.QuadPart, pszSize, 10);
  156. }
  157. PadDirField(pszSize, pad);
  158. if (FAILED(hr = pstrResponse->Append(pszSize)))
  159. {
  160. return hr;
  161. }
  162. }
  163. STACK_STRA (straFileName, 16);
  164. if (FAILED(hr = pstrResponse->Append("<A HREF=\"")) ||
  165. FAILED(hr = pstrResponse->Append(strURL)) ||
  166. FAILED(hr = straFileName.CopyWToUTF8(pFileData->cFileName)) ||
  167. FAILED(hr = pstrResponse->Append(straFileName)))
  168. {
  169. return hr;
  170. }
  171. if ((pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  172. FAILED(hr = pstrResponse->Append("/")))
  173. {
  174. return hr;
  175. }
  176. if (FAILED(hr = pstrResponse->Append("\">")))
  177. {
  178. return hr;
  179. }
  180. if (FAILED(hr = straFileName.CopyWToUTF8Unescaped(pFileData->cFileName)))
  181. {
  182. return hr;
  183. }
  184. //
  185. // If the show extension flag is not set, then strip it. If the
  186. // file name begins with a dot, then don't strip it.
  187. //
  188. if (!(dwDirBrowseFlags & DIRBROW_SHOW_EXTENSION))
  189. {
  190. int dotIndex = straFileName.QueryCCH() - 1;
  191. while ((dotIndex > 0) &&
  192. (straFileName.QueryStr()[dotIndex] != '.'))
  193. {
  194. dotIndex--;
  195. }
  196. if (dotIndex > 0)
  197. straFileName.SetLen(dotIndex);
  198. }
  199. if (FAILED(hr = pstrResponse->Append(straFileName)) ||
  200. FAILED(hr = pstrResponse->Append("</A><br>")))
  201. {
  202. return hr;
  203. }
  204. return S_OK;
  205. }
  206. int
  207. __cdecl
  208. SortDirectoryEntries(const void *elem1,
  209. const void *elem2)
  210. {
  211. return _wcsicmp(((WIN32_FIND_DATA *)elem1)->cFileName,
  212. ((WIN32_FIND_DATA *)elem2)->cFileName);
  213. }
  214. HRESULT
  215. W3_STATIC_FILE_HANDLER::HandleDirectoryListing(
  216. IN W3_CONTEXT * pContext,
  217. OUT BOOL * pfHandled
  218. )
  219. {
  220. DBG_ASSERT(pfHandled != NULL);
  221. DBG_ASSERT(pContext != NULL);
  222. W3_RESPONSE *pResponse = pContext->QueryResponse();
  223. DBG_ASSERT(pResponse != NULL);
  224. URL_CONTEXT *pUrlContext = pContext->QueryUrlContext();
  225. DBG_ASSERT(pUrlContext != NULL);
  226. DWORD dwDirBrowseFlags = pUrlContext->QueryMetaData()->QueryDirBrowseFlags();
  227. HRESULT hr;
  228. // Append a '*' to get all files in the directory
  229. STACK_STRU (strPhysical, MAX_PATH);
  230. if (FAILED(hr = strPhysical.Copy(
  231. pUrlContext->QueryPhysicalPath()->QueryStr())))
  232. {
  233. return hr;
  234. }
  235. LPWSTR starString;
  236. if (strPhysical.QueryStr()[strPhysical.QueryCCH() - 1] == L'\\')
  237. starString = L"*";
  238. else
  239. starString = L"\\*";
  240. if (FAILED(hr = strPhysical.Append(starString)))
  241. {
  242. return hr;
  243. }
  244. STACK_STRA (strHostName, 16);
  245. if (FAILED(hr = GetServerVariableServerName(pContext, &strHostName)))
  246. {
  247. return hr;
  248. }
  249. STACK_STRU (strURL, 128);
  250. STACK_STRA (straURL, 128);
  251. STACK_STRA (straUTF8UnescapedURL, 128);
  252. if (FAILED(hr = pContext->QueryRequest()->GetUrl(&strURL)))
  253. {
  254. return hr;
  255. }
  256. if ((strURL.QueryStr()[strURL.QueryCCH() - 1] != L'/') &&
  257. FAILED(hr = strURL.Append(L"/")))
  258. {
  259. return hr;
  260. }
  261. if (FAILED(hr = straURL.CopyWToUTF8(strURL.QueryStr())) ||
  262. FAILED(hr = straUTF8UnescapedURL.CopyWToUTF8Unescaped(strURL.QueryStr())))
  263. {
  264. return hr;
  265. }
  266. //
  267. // Write hardcoded HTML header
  268. //
  269. if (FAILED(hr = m_strDirlistResponse.Copy("<html><head>")) ||
  270. FAILED(hr = m_strDirlistResponse.Append("<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">")) ||
  271. FAILED(hr = m_strDirlistResponse.Append("<title>")) ||
  272. FAILED(hr = m_strDirlistResponse.Append(strHostName)) ||
  273. FAILED(hr = m_strDirlistResponse.Append(" - ")) ||
  274. FAILED(hr = m_strDirlistResponse.Append(straUTF8UnescapedURL)) ||
  275. FAILED(hr = m_strDirlistResponse.Append("</title></head><body><H1>")) ||
  276. FAILED(hr = m_strDirlistResponse.Append(strHostName)) ||
  277. FAILED(hr = m_strDirlistResponse.Append(" - ")) ||
  278. FAILED(hr = m_strDirlistResponse.Append(straUTF8UnescapedURL)) ||
  279. FAILED(hr = m_strDirlistResponse.Append("</H1><hr>\r\n\r\n<pre>")))
  280. {
  281. return hr;
  282. }
  283. //
  284. // Create the link to the parent directory, if applicable
  285. //
  286. if (straURL.QueryCCH() >= 3)
  287. {
  288. int cchParentIndex;
  289. for (cchParentIndex = straURL.QueryCCH() - 2;
  290. (cchParentIndex >= 0) &&
  291. (straURL.QueryStr()[cchParentIndex] != L'/');
  292. cchParentIndex--);
  293. if ( cchParentIndex != -1 )
  294. {
  295. if (FAILED(hr = m_strDirlistResponse.Append("<A HREF=\"")) ||
  296. FAILED(hr = m_strDirlistResponse.Append(straURL.QueryStr(), cchParentIndex + 1)) ||
  297. FAILED(hr = m_strDirlistResponse.Append("\">[To Parent Directory]</A><br><br>")))
  298. {
  299. return hr;
  300. }
  301. }
  302. }
  303. BUFFER bufFileData(8192);
  304. DWORD numFiles = 0;
  305. HANDLE hFindFile = FindFirstFile(strPhysical.QueryStr(),
  306. (WIN32_FIND_DATA *)bufFileData.QueryPtr());
  307. if (hFindFile == INVALID_HANDLE_VALUE)
  308. {
  309. return HRESULT_FROM_WIN32(GetLastError());
  310. }
  311. pResponse->SetStatus(HttpStatusOk);
  312. if (FAILED(hr = pResponse->SetHeaderByReference(HttpHeaderContentType,
  313. HEADER("text/html"))))
  314. {
  315. DBG_REQUIRE(FindClose(hFindFile));
  316. return hr;
  317. }
  318. for (;;)
  319. {
  320. WIN32_FIND_DATA *pFileData = (WIN32_FIND_DATA *)bufFileData.QueryPtr() + numFiles;
  321. if (((pFileData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0) &&
  322. wcscmp(pFileData->cFileName, L".") &&
  323. wcscmp(pFileData->cFileName, L".."))
  324. {
  325. numFiles++;
  326. if (!bufFileData.Resize(sizeof(WIN32_FIND_DATA)*(numFiles + 1),
  327. sizeof(WIN32_FIND_DATA)*(numFiles + 1)))
  328. {
  329. FindClose(hFindFile);
  330. return HRESULT_FROM_WIN32(GetLastError());
  331. }
  332. }
  333. if (!FindNextFile(hFindFile,
  334. (WIN32_FIND_DATA *)bufFileData.QueryPtr() + numFiles))
  335. {
  336. DWORD err = GetLastError();
  337. if (err == ERROR_NO_MORE_FILES)
  338. break;
  339. FindClose(hFindFile);
  340. return HRESULT_FROM_WIN32(err);
  341. }
  342. }
  343. DBG_REQUIRE(FindClose(hFindFile));
  344. //
  345. // Now sort the directory-entries
  346. //
  347. qsort(bufFileData.QueryPtr(),
  348. numFiles,
  349. sizeof(WIN32_FIND_DATA),
  350. SortDirectoryEntries);
  351. for (DWORD i=0; i<numFiles; i++)
  352. {
  353. //
  354. // Add the entry for this file
  355. //
  356. if (FAILED(hr = AddFileEntry(straURL,
  357. (WIN32_FIND_DATA *)bufFileData.QueryPtr() + i,
  358. dwDirBrowseFlags,
  359. &m_strDirlistResponse)))
  360. {
  361. return hr;
  362. }
  363. }
  364. if (FAILED(hr = m_strDirlistResponse.Append("</pre><hr></body></html>")))
  365. {
  366. return hr;
  367. }
  368. if (FAILED(hr = pResponse->AddMemoryChunkByReference(m_strDirlistResponse.QueryStr(),
  369. m_strDirlistResponse.QueryCCH())))
  370. {
  371. return hr;
  372. }
  373. *pfHandled = TRUE;
  374. return S_OK;
  375. }