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.

429 lines
12 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=sizeof(name);
  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, mid);
  138. WCHAR name[MAXPATH];
  139. int name_len=sizeof(name);
  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=sizeof(name);
  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. xFsClose(fd);
  190. }
  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_COMMIT, PAGE_READWRITE);
  228. if (buf == NULL) {
  229. FsLogError(("Unable to allocate write buffer to replay\n"));
  230. err = STATUS_TRANSACTION_ABORTED;
  231. goto done;
  232. }
  233. off.LowPart = lrec->offset;
  234. off.HighPart = 0;
  235. // read local data. todo: what if the file is locked?
  236. err = NtReadFile(shdl, NULL, NULL, NULL, &ios, buf,
  237. lrec->length, &off, NULL);
  238. if (err == STATUS_PENDING) {
  239. EventWait(shdl);
  240. }
  241. if (ios.Status != STATUS_SUCCESS) {
  242. FsLogUndo(("Read failed for replay %x\n", ios.Status));
  243. err = STATUS_TRANSACTION_ABORTED;
  244. goto done;
  245. }
  246. } else {
  247. buf = NULL;
  248. ios.Information = 0;
  249. }
  250. sz = (ULONG) ios.Information;
  251. off.LowPart = lrec->offset;
  252. off.HighPart = 0;
  253. if (sz > 0) {
  254. err = NtWriteFile(dhdl, NULL, NULL, (PVOID) NULL,
  255. &ios, buf, sz, &off, NULL);
  256. } else {
  257. FILE_END_OF_FILE_INFORMATION x;
  258. x.EndOfFile = off;
  259. err = NtSetInformationFile(dhdl, &ios,
  260. (char *) &x, sizeof(x),
  261. FileEndOfFileInformation);
  262. }
  263. if (err == STATUS_PENDING) {
  264. EventWait(dhdl);
  265. err = ios.Status;
  266. }
  267. sz = (ULONG) ios.Information;
  268. // check if we have the same size, otherwise abort
  269. if (sz != lrec->length) {
  270. FsLogError(("Write sz mismatch, %d expected %d\n", sz, lrec->length));
  271. err = STATUS_TRANSACTION_ABORTED;
  272. }
  273. } else if (err == STATUS_OBJECT_PATH_NOT_FOUND) {
  274. // if we can't find file in the master disk, the file/dir
  275. // must have already been delete.
  276. err = STATUS_SUCCESS;
  277. }
  278. done:
  279. if (buf != NULL) {
  280. VirtualFree(buf, 0, MEM_RELEASE);
  281. }
  282. if (shdl != INVALID_HANDLE_VALUE)
  283. xFsClose(shdl);
  284. if (dhdl != INVALID_HANDLE_VALUE)
  285. xFsClose(dhdl);
  286. FsLogUndo(("Undo write offset %d len %d err %x\n",
  287. lrec->offset, lrec->length, err));
  288. return err;
  289. }
  290. FsReplayHandler_t FsUndoCallTable[] = {
  291. fs_undo_create,
  292. fs_undo_setattr,
  293. fs_undo_write,
  294. fs_undo_mkdir,
  295. fs_undo_remove,
  296. fs_undo_rename
  297. };
  298. NTSTATUS
  299. FsUndoXid(VolInfo_t *volinfo, int nid, PVOID arg, int action, int mid)
  300. {
  301. fs_log_rec_t *p = (fs_log_rec_t *) arg;
  302. NTSTATUS err;
  303. fs_id_t *fs_id;
  304. HANDLE vhdl;
  305. vhdl = FS_GET_VOL_HANDLE(volinfo, mid);
  306. if (vhdl == INVALID_HANDLE_VALUE) {
  307. FsLogUndo(("FsUndoXid Failed to get crs handle %d\n",
  308. mid));
  309. return STATUS_TRANSACTION_ABORTED;
  310. }
  311. vhdl = FS_GET_VOL_HANDLE(volinfo, nid);
  312. if (vhdl == INVALID_HANDLE_VALUE) {
  313. FsLogUndo(("FsUndoXid Failed to get crs handle %d\n", nid));
  314. return STATUS_TRANSACTION_ABORTED;
  315. }
  316. fs_id = &p->fs_id;
  317. FsLogUndo(("Undo action %d nid %d objid %I64x:%I64x\n", p->command,
  318. nid,
  319. (*fs_id)[0], (*fs_id)[1]));
  320. err = FsUndoCallTable[p->command](volinfo, p, nid, mid);
  321. FsLogUndo(("Undo Status %x\n", err));
  322. return err;
  323. }