Source code of Windows XP (NT5)
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.

431 lines
10 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. undo.c
  5. Abstract:
  6. Implements undo of records during replica recovery
  7. Author:
  8. Ahmed Mohamed (ahmedm) 1-Feb-2000
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntdef.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <ntddvol.h>
  18. #include <string.h>
  19. #include <assert.h>
  20. #include "fs.h"
  21. #include "fsp.h"
  22. #include "fsutil.h"
  23. NTSTATUS
  24. fs_undo_create(VolInfo_t *volinfo,
  25. fs_log_rec_t *lrec, int nid, int mid)
  26. {
  27. NTSTATUS err;
  28. // find the objectid
  29. HANDLE vfd = FS_GET_VOL_HANDLE(volinfo, nid);
  30. WCHAR name[MAXPATH];
  31. int name_len = sizeof(name);
  32. name[0] = '\0';
  33. // note: use id instead of fs_id since we don't have fs_id till
  34. // a prepare has committed.
  35. FsLogUndo(("fs_undo_create: try %I64x:%I64x\n",
  36. lrec->id[0], lrec->id[1]));
  37. err = xFsGetPathById(vfd, &lrec->id, name, &name_len);
  38. if (err == STATUS_SUCCESS) {
  39. int relative_name_len;
  40. LPWSTR relative_name;
  41. relative_name = xFsBuildRelativePath(volinfo, nid, name);
  42. relative_name_len = wcslen(relative_name);
  43. err = xFsDelete(vfd, relative_name, relative_name_len);
  44. } else if (err == STATUS_OBJECT_PATH_NOT_FOUND) {
  45. // if we can't find file in the master disk, the file/dir
  46. // must have already been delete. Just return success, since
  47. // we are trying to remove this file anyway.
  48. err = STATUS_SUCCESS;
  49. }
  50. FsLogUndo(("fs_undo_create: status %x\n", err));
  51. return err;
  52. }
  53. NTSTATUS
  54. fs_undo_setattr(VolInfo_t *volinfo,
  55. fs_log_rec_t *lrec, int nid, int mid)
  56. {
  57. NTSTATUS err;
  58. // find the objectid
  59. HANDLE vfd = FS_GET_VOL_HANDLE(volinfo, nid);
  60. HANDLE mvfd = FS_GET_VOL_HANDLE(volinfo, mid);
  61. WCHAR name[MAXPATH];
  62. int name_len;
  63. name[0] = '\0';
  64. FsLogUndo(("fs_undo_setattr: try %I64x:%I64x\n",
  65. lrec->fs_id[0], lrec->fs_id[1]));
  66. err = xFsGetPathById(mvfd, &lrec->fs_id, name, &name_len);
  67. if (err == STATUS_SUCCESS) {
  68. int relative_name_len;
  69. LPWSTR relative_name;
  70. HANDLE fd;
  71. FILE_NETWORK_OPEN_INFORMATION attr;
  72. FILE_BASIC_INFORMATION new_attr;
  73. // build relative name and get current attribute from
  74. // master disk and apply it to 'nid' disk
  75. relative_name = xFsBuildRelativePath(volinfo, mid, name);
  76. relative_name_len = wcslen(relative_name);
  77. err = xFsQueryAttrName(mvfd, relative_name, relative_name_len,
  78. &attr);
  79. if (err == STATUS_SUCCESS) {
  80. // we now apply attribute to nid disk
  81. err = xFsOpenWA(&fd, vfd, relative_name, relative_name_len);
  82. if (err == STATUS_SUCCESS) {
  83. new_attr.CreationTime = attr.CreationTime;
  84. new_attr.LastAccessTime = attr.LastAccessTime;
  85. new_attr.LastWriteTime = attr.LastWriteTime;
  86. new_attr.ChangeTime = attr.ChangeTime;
  87. new_attr.FileAttributes = attr.FileAttributes;
  88. err = xFsSetAttr(fd, &new_attr);
  89. xFsClose(fd);
  90. }
  91. }
  92. } else if (err == STATUS_OBJECT_PATH_NOT_FOUND) {
  93. // if we can't find file in the master disk, the file/dir
  94. // must have already been delete. Just return success, since
  95. // we will get to remove this dir/file anyway during the
  96. // replay phase
  97. err = STATUS_SUCCESS;
  98. }
  99. FsLogUndo(("fs_undo_setattr: status %x\n", err));
  100. return err;
  101. }
  102. NTSTATUS
  103. fs_undo_mkdir(VolInfo_t *volinfo,
  104. fs_log_rec_t *lrec, int nid, int mid)
  105. {
  106. NTSTATUS err;
  107. // find the objectid
  108. HANDLE vfd = FS_GET_VOL_HANDLE(volinfo, nid);
  109. WCHAR name[MAXPATH];
  110. int name_len = sizeof(name);
  111. name[0] = '\0';
  112. // note: use id instead of fs_id since we don't have fs_id till
  113. // a prepare has committed.
  114. FsLogUndo(("fs_undo_mkdir: try %I64x:%I64x\n",
  115. lrec->id[0], lrec->id[1]));
  116. err = xFsGetPathById(vfd, &lrec->id, name, &name_len);
  117. if (err == STATUS_SUCCESS) {
  118. int relative_name_len;
  119. WCHAR *relative_name;
  120. relative_name = xFsBuildRelativePath(volinfo, nid, name);
  121. relative_name_len = wcslen(relative_name);
  122. err = xFsDelete(vfd, relative_name, relative_name_len);
  123. }
  124. FsLogUndo(("fs_undo_mkdir: status %x\n", err));
  125. return err;
  126. }
  127. NTSTATUS
  128. fs_undo_remove(VolInfo_t *volinfo,
  129. fs_log_rec_t *lrec, int nid, int mid)
  130. {
  131. // we need to recreate the file with same name and attributes.
  132. // if file is not a directory, we also need to copy data
  133. // from master disk to nid disk
  134. NTSTATUS err;
  135. // find the objectid
  136. HANDLE vfd = FS_GET_VOL_HANDLE(volinfo, nid);
  137. HANDLE mvfd = FS_GET_VOL_HANDLE(volinfo, nid);
  138. WCHAR name[MAXPATH];
  139. int name_len;
  140. name[0] = '\0';
  141. FsLogUndo(("fs_undo_remove: try %I64x:%I64x\n",
  142. lrec->fs_id[0], lrec->fs_id[1]));
  143. err = xFsGetPathById(mvfd, &lrec->fs_id, name, &name_len);
  144. if (err == STATUS_SUCCESS) {
  145. int relative_name_len;
  146. WCHAR *relative_name;
  147. // build relative name
  148. relative_name = xFsBuildRelativePath(volinfo, mid, name);
  149. relative_name_len = wcslen(relative_name);
  150. // duplicate file or dir
  151. err = xFsDupFile(mvfd, vfd, relative_name, relative_name_len, FALSE);
  152. } else if (err == STATUS_OBJECT_PATH_NOT_FOUND) {
  153. // if we can't find file in the master disk, the file/dir
  154. // must have already been delete.
  155. err = STATUS_SUCCESS;
  156. }
  157. FsLogUndo(("fs_undo_remove: status %x\n", err));
  158. return err;
  159. }
  160. NTSTATUS
  161. fs_undo_rename(VolInfo_t *volinfo,
  162. fs_log_rec_t *lrec, int nid, int mid)
  163. {
  164. // we need to recreate the file with same name and attributes.
  165. // if file is not a directory, we also need to copy data
  166. // from master disk to nid disk
  167. NTSTATUS err;
  168. // find the objectid
  169. HANDLE vfd = FS_GET_VOL_HANDLE(volinfo, nid);
  170. HANDLE mvfd = FS_GET_VOL_HANDLE(volinfo, mid);
  171. WCHAR name[MAXPATH];
  172. int name_len;
  173. name[0] = '\0';
  174. FsLogUndo(("fs_undo_rename: try %I64x:%I64x\n",
  175. lrec->fs_id[0], lrec->fs_id[1]));
  176. err = xFsGetPathById(mvfd, &lrec->fs_id, name, &name_len);
  177. if (err == STATUS_SUCCESS) {
  178. int relative_name_len;
  179. WCHAR *relative_name;
  180. HANDLE fd;
  181. // build relative name and get current attribute from
  182. // master disk
  183. relative_name = xFsBuildRelativePath(volinfo, mid, name);
  184. relative_name_len = wcslen(relative_name);
  185. // we open the file on the nid disk
  186. err = xFsGetHandleById(vfd, &lrec->fs_id, FILE_GENERIC_WRITE, &fd);
  187. if (err == STATUS_SUCCESS) {
  188. err = xFsRename(fd, vfd, relative_name, relative_name_len);
  189. }
  190. xFsClose(fd);
  191. } else if (err == STATUS_OBJECT_PATH_NOT_FOUND) {
  192. // if we can't find file in the master disk, the file/dir
  193. // must have already been delete.
  194. err = STATUS_SUCCESS;
  195. }
  196. FsLogUndo(("fs_undo_rename: status %x\n", err));
  197. return err;
  198. }
  199. NTSTATUS
  200. fs_undo_write(VolInfo_t *volinfo, fs_log_rec_t *lrec, int nid, int mid)
  201. {
  202. NTSTATUS err;
  203. IO_STATUS_BLOCK ios;
  204. HANDLE shdl = INVALID_HANDLE_VALUE;
  205. HANDLE dhdl = INVALID_HANDLE_VALUE;
  206. WCHAR *buf = NULL;
  207. HANDLE vfd = FS_GET_VOL_HANDLE(volinfo, nid);
  208. HANDLE mvfd = FS_GET_VOL_HANDLE(volinfo, mid);
  209. FsLogUndo(("fs_undo_write: %I64x:%I64x\n", lrec->fs_id[0],
  210. lrec->fs_id[1]));
  211. // get the master file
  212. err = xFsGetHandleById(mvfd, &lrec->fs_id, FILE_GENERIC_READ, &shdl);
  213. if (err == STATUS_SUCCESS) {
  214. ULONG sz = 0;
  215. LARGE_INTEGER off;
  216. // get nid disk file
  217. err = xFsGetHandleById(vfd, &lrec->fs_id, FILE_GENERIC_WRITE, &dhdl);
  218. if (err != STATUS_SUCCESS) {
  219. // this is a very bad error, must abort now
  220. FsLogUndo(("Aborting replay_write err %x\n", err));
  221. err = STATUS_TRANSACTION_ABORTED;
  222. goto done;
  223. }
  224. // we need to read the new data from the sfd first
  225. if (lrec->length > 0) {
  226. // allocate buf
  227. buf = VirtualAlloc(NULL, lrec->length, MEM_RESERVE|MEM_COMMIT,
  228. PAGE_READWRITE);
  229. if (buf == NULL) {
  230. FsLogError(("Unable to allocate write buffer to replay\n"));
  231. err = STATUS_TRANSACTION_ABORTED;
  232. goto done;
  233. }
  234. off.LowPart = lrec->offset;
  235. off.HighPart = 0;
  236. // read local data. todo: what if the file is locked?
  237. err = NtReadFile(shdl, NULL, NULL, NULL, &ios, buf,
  238. lrec->length, &off, NULL);
  239. if (err == STATUS_PENDING) {
  240. EventWait(shdl);
  241. }
  242. if (ios.Status != STATUS_SUCCESS) {
  243. FsLogUndo(("Read failed for replay %x\n", ios.Status));
  244. err = STATUS_TRANSACTION_ABORTED;
  245. goto done;
  246. }
  247. } else {
  248. buf = NULL;
  249. ios.Information = 0;
  250. }
  251. sz = (ULONG) ios.Information;
  252. off.LowPart = lrec->offset;
  253. off.HighPart = 0;
  254. if (sz > 0) {
  255. err = NtWriteFile(dhdl, NULL, NULL, (PVOID) NULL,
  256. &ios, buf, sz, &off, NULL);
  257. } else {
  258. FILE_END_OF_FILE_INFORMATION x;
  259. x.EndOfFile = off;
  260. err = NtSetInformationFile(dhdl, &ios,
  261. (char *) &x, sizeof(x),
  262. FileEndOfFileInformation);
  263. }
  264. if (err == STATUS_PENDING) {
  265. EventWait(dhdl);
  266. err = ios.Status;
  267. }
  268. sz = (ULONG) ios.Information;
  269. // check if we have the same size, otherwise abort
  270. if (sz != lrec->length) {
  271. FsLogError(("Write sz mismatch, %d expected %d\n", sz, lrec->length));
  272. err = STATUS_TRANSACTION_ABORTED;
  273. }
  274. } else if (err == STATUS_OBJECT_PATH_NOT_FOUND) {
  275. // if we can't find file in the master disk, the file/dir
  276. // must have already been delete.
  277. err = STATUS_SUCCESS;
  278. }
  279. done:
  280. if (buf != NULL) {
  281. VirtualFree(buf, 0, MEM_DECOMMIT|MEM_RELEASE);
  282. }
  283. if (shdl != INVALID_HANDLE_VALUE)
  284. xFsClose(shdl);
  285. if (dhdl != INVALID_HANDLE_VALUE)
  286. xFsClose(dhdl);
  287. FsLogUndo(("Undo write offset %d len %d err %x\n",
  288. lrec->offset, lrec->length, err));
  289. return err;
  290. }
  291. FsReplayHandler_t FsUndoCallTable[] = {
  292. fs_undo_create,
  293. fs_undo_setattr,
  294. fs_undo_write,
  295. fs_undo_mkdir,
  296. fs_undo_remove,
  297. fs_undo_rename
  298. };
  299. NTSTATUS
  300. FsUndoXid(VolInfo_t *volinfo, int nid, PVOID arg, int action, int mid)
  301. {
  302. fs_log_rec_t *p = (fs_log_rec_t *) arg;
  303. NTSTATUS err;
  304. fs_id_t *fs_id;
  305. HANDLE vhdl;
  306. vhdl = FS_GET_VOL_HANDLE(volinfo, mid);
  307. if (vhdl == INVALID_HANDLE_VALUE) {
  308. FsLogUndo(("FsUndoXid Failed to get crs handle %d\n",
  309. mid));
  310. return STATUS_TRANSACTION_ABORTED;
  311. }
  312. vhdl = FS_GET_VOL_HANDLE(volinfo, nid);
  313. if (vhdl == INVALID_HANDLE_VALUE) {
  314. FsLogUndo(("FsUndoXid Failed to get crs handle %d\n", nid));
  315. return STATUS_TRANSACTION_ABORTED;
  316. }
  317. fs_id = &p->fs_id;
  318. FsLogUndo(("Undo action %d nid %d objid %I64x:%I64x\n", p->command,
  319. nid,
  320. (*fs_id)[0], (*fs_id)[1]));
  321. err = FsUndoCallTable[p->command](volinfo, p, nid, mid);
  322. FsLogUndo(("Undo Status %x\n", err));
  323. return err;
  324. }