Guest User

Untitled

a guest
Jun 20th, 2018
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.48 KB | None | 0 0
  1. Index: repy/emulfile.py
  2. ===================================================================
  3. --- repy/emulfile.py (revision 2330)
  4. +++ repy/emulfile.py (working copy)
  5. @@ -16,6 +16,9 @@
  6. import os
  7. import idhelper
  8.  
  9. +# needed for locking the fileinfo hash
  10. +import threading
  11. +
  12. # I need to rename file so that the checker doesn't complain...
  13. myfile = file
  14.  
  15. @@ -72,10 +75,18 @@
  16. # Handle the case where the file is open via an exception to prevent the user
  17. # from removing a file to circumvent resource accounting
  18.  
  19. + fileinfolock.acquire()
  20. for filehandle in fileinfo:
  21. if filename == fileinfo[filehandle]['filename']:
  22. + fileinfolock.release()
  23. raise Exception, 'File "'+filename+'" is open with handle "'+filehandle+'"'
  24. - return os.remove(filename)
  25. +
  26. + try:
  27. + result = os.remove(filename)
  28. + finally:
  29. + fileinfolock.release()
  30. +
  31. + return result
  32.  
  33.  
  34.  
  35. @@ -85,34 +96,129 @@
  36. def emulated_open(filename, mode="rb"):
  37. """
  38. <Purpose>
  39. - Allows the user program to open a file safely. This function is meant
  40. - to resemble the builtin "open"
  41. + Allows the user program to open a file safely. This function is meant
  42. + to resemble the builtin "open".
  43.  
  44. <Arguments>
  45. filename:
  46. - The file that should be operated on
  47. + The file that should be operated on.
  48. mode:
  49. - The mode (see open)
  50. + The mode (see open).
  51.  
  52. <Exceptions>
  53. - As with open, this may raise a number of errors
  54. + As with open, this may raise a number of errors. Additionally:
  55.  
  56. + TypeError if the mode is not a string.
  57. + ValueError if the modestring is invalid.
  58. +
  59. <Side Effects>
  60. - Opens a file on disk, using a file descriptor. When opened with "w"
  61. + Opens a file on disk, using a file descriptor. When opened with "w"
  62. it will truncate the existing file.
  63.  
  64. <Returns>
  65. + A file-like object.
  66. + """
  67. +
  68. + if type(mode) is not str:
  69. + raise TypeError("Attempted to open file with invalid mode (must be a string).")
  70. +
  71. + # We just filter out 'b' / 't' in modestrings because emulated_file opens
  72. + # everything in binary mode for us.
  73. +
  74. + originalmode = mode
  75. +
  76. + if 'b' in mode:
  77. + mode = mode.replace('b','')
  78. +
  79. + if 't' in mode:
  80. + mode = mode.replace('t','')
  81. +
  82. + # Now we use our very safe, cross-platform open-like function and other
  83. + # file-object methods to emulate ANSI file modes.
  84. +
  85. + file_object = None
  86. + if mode == "r":
  87. + file_object = safe_open(filename, "r")
  88. +
  89. + elif mode == "r+":
  90. + file_object = safe_open(filename, "rw")
  91. +
  92. + elif mode == "w" or mode == "w+":
  93. + file_object = safe_open(filename, "rw", create=True)
  94. + fileinfo[file_object.filehandle]['fobj'].truncate()
  95. +
  96. + elif mode == "a" or mode == "a+":
  97. + file_object = safe_open(filename, "rw", create=True)
  98. + file_object.seek(0, os.SEEK_END)
  99. +
  100. +
  101. + if file_object is None:
  102. + raise ValueError("Invalid or unsupported mode ('%s') passed to open()." % originalmode)
  103. +
  104. + return file_object
  105. +
  106. +
  107. +
  108. +
  109. +def safe_open(filename, mode="r", create=False):
  110. + """
  111. + <Purpose>
  112. + Allows the user program to open a file safely. This function is not
  113. + meant to resemble the builtin "open".
  114. +
  115. + <Arguments>
  116. + filename:
  117. + The file that should be operated on
  118. + mode:
  119. + The mode:
  120. + "r": Open the file for reading.
  121. + "rw": Open the file for reading and writing.
  122. +
  123. + These are the only valid modes accepted by this version of
  124. + open(). Note: files are always opened in "binary" mode.
  125. + create:
  126. + If True, create the file if it doesn't exist already.
  127. +
  128. + <Exceptions>
  129. + As with open, this may raise a number of errors. Additionally:
  130. +
  131. + ValueError is raised if this is passed an invalid mode.
  132. +
  133. + <Side Effects>
  134. + Opens a file on disk, using a file descriptor.
  135. +
  136. + <Returns>
  137. A file-like object
  138. """
  139.  
  140. - restrictions.assertisallowed('open',filename,mode)
  141. + # Only allow 'r', 'rw', and 'U'.
  142.  
  143. - return emulated_file(filename, mode)
  144. + actual_mode = None
  145. + if mode == "r":
  146. + actual_mode = "rb"
  147. + elif mode == "rw":
  148. + actual_mode = "r+b"
  149. +
  150. + if actual_mode is None:
  151. + raise ValueError("Valid modes for opening a file in repy are 'r' and 'rw'.")
  152.  
  153. + restrictions.assertisallowed('open', filename, actual_mode)
  154.  
  155. + if create and not os.path.exists(filename):
  156. + # Create a file by opening it in write mode and then closing it.
  157. + restrictions.assertisallowed('open', filename, "wb")
  158.  
  159. + create_file = emulated_file(filename, "wb")
  160. + create_file.close()
  161. +
  162. + return emulated_file(filename, actual_mode)
  163. +
  164. +
  165. +
  166. +
  167. # This keeps the state for the files (the actual objects, etc.)
  168. fileinfo = {}
  169. +fileinfolock = threading.Lock()
  170.  
  171.  
  172.  
  173. @@ -171,15 +277,37 @@
  174. # It must have a 'b'
  175. mode = mode + 'b'
  176.  
  177. - assert_is_allowed_filename(filename)
  178. + # Here we are checking that we only open a given file once in 'write' mode
  179. + # so that file access is more uniform across platforms. (On Microsoft
  180. + # Windows, for example, writing to the same file from two different file-
  181. + # handles throws an error because of the way Windows (by default) locks
  182. + # files opened for writing.)
  183. + fileinfolock.acquire()
  184.  
  185. - self.filehandle = idhelper.getuniqueid()
  186. + try:
  187. + # Check the entire fileinfo dictionary for the same file already being
  188. + # open.
  189. + for fileinfokey in fileinfo.keys():
  190.  
  191. - nanny.tattle_add_item('filesopened',self.filehandle)
  192. + # If the filename matches this one, raise an exception.
  193. + if os.path.abspath(fileinfo[fileinfokey]['filename']) == \
  194. + os.path.abspath(filename)
  195. + raise ArgumentError(\
  196. + "A file is only allowed to have one open filehandle.")
  197.  
  198. - fileinfo[self.filehandle] = {'filename':filename, 'mode':mode,'fobj':myfile(filename,mode)}
  199. - self.name=filename
  200. - self.mode=mode
  201. + assert_is_allowed_filename(filename)
  202. +
  203. + self.filehandle = idhelper.getuniqueid()
  204. +
  205. + nanny.tattle_add_item('filesopened',self.filehandle)
  206. +
  207. + fileinfo[self.filehandle] = {'filename':filename, 'mode':mode,'fobj':myfile(filename,mode)}
  208. + self.name=filename
  209. + self.mode=mode
  210. +
  211. + finally:
  212. + fileinfolock.release()
  213. +
  214. return None
  215.  
  216.  
  217. @@ -203,11 +331,16 @@
  218.  
  219. nanny.tattle_remove_item('filesopened',myfilehandle)
  220.  
  221. - returnvalue = fileinfo[myfilehandle]['fobj'].close()
  222. + fileinfolock.acquire()
  223. + try:
  224. + returnvalue = fileinfo[myfilehandle]['fobj'].close()
  225.  
  226. - # delete the filehandle
  227. - del fileinfo[myfilehandle]
  228. + # delete the filehandle
  229. + del fileinfo[myfilehandle]
  230.  
  231. + finally:
  232. + fileinfolock.release()
  233. +
  234. return returnvalue
  235.  
  236.  
  237. Index: repy/tests/z_testopen.py
  238. ===================================================================
  239. --- repy/tests/z_testopen.py (revision 0)
  240. +++ repy/tests/z_testopen.py (revision 0)
  241. @@ -0,0 +1,55 @@
  242. +# Some tests to ensure open() behaves like our definition.
  243. +
  244. +SEEK_SET = 0 # Absolute
  245. +SEEK_CUR = 1 # Relative
  246. +SEEK_END = 2 # End of the file
  247. +
  248. +try:
  249. + # Test basic writing / reading
  250. + fro = open("junk_test.out", "w+")
  251. + fro.write("hi!")
  252. + fro.flush()
  253. + fro.seek(0, SEEK_SET)
  254. + contents = fro.read()
  255. + fro.close()
  256. + if contents != "hi!":
  257. + print "Failed to write to / read from file!"
  258. +
  259. + fro = open("junk_test.out", "r")
  260. + contents = fro.read()
  261. + fro.close()
  262. + if contents != "hi!":
  263. + print "Failed to write to / read from file!"
  264. +
  265. + # Test "w" semantics
  266. + fro = open("junk_test.out", "w+")
  267. + contents = fro.read()
  268. + if contents != "":
  269. + print "Write mode fails to truncate file!"
  270. + fro.seek(0, SEEK_SET)
  271. + fro.write("Testing 123")
  272. + fro.close()
  273. +
  274. + # Test append
  275. + fro = open("junk_test.out", "a+")
  276. + fro.write("abc")
  277. + fro.flush()
  278. + fro.seek(0, SEEK_SET)
  279. + contents = fro.read()
  280. + fro.close()
  281. + if contents != "Testing 123abc":
  282. + print "Append mode fails to append!"
  283. +
  284. + # Test universal newlines
  285. + fro = open("junk_test.out", "w+")
  286. + fro.write("Hello\rMac\r\nWindows\nUnix World!")
  287. + fro.close()
  288. + fro = open("junk_test.out", "rU")
  289. + contents = fro.read()
  290. + fro.close()
  291. + if contents != "Hello\nMac\nWindows\nUnix World!":
  292. + print "Universal readline mode fails to read universally!"
  293. +
  294. +finally:
  295. + if "junk_test.out" in listdir():
  296. + removefile("junk_test.out")
Add Comment
Please, Sign In to add comment