| 
									
										
										
										
											2003-12-02 12:31:09 +00:00
										 |  |  | # _emx_link.py | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Written by Andrew I MacIntyre, December 2002. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  | """_emx_link.py is a simplistic emulation of the Unix link(2) library routine
 | 
					
						
							| 
									
										
										
										
											2003-12-02 12:31:09 +00:00
										 |  |  | for creating so-called hard links.  It is intended to be imported into | 
					
						
							|  |  |  | the os module in place of the unimplemented (on OS/2) Posix link() | 
					
						
							|  |  |  | function (os.link()). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | We do this on OS/2 by implementing a file copy, with link(2) semantics:- | 
					
						
							|  |  |  |   - the target cannot already exist; | 
					
						
							|  |  |  |   - we hope that the actual file open (if successful) is actually | 
					
						
							|  |  |  |     atomic... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Limitations of this approach/implementation include:- | 
					
						
							|  |  |  |   - no support for correct link counts (EMX stat(target).st_nlink | 
					
						
							|  |  |  |     is always 1); | 
					
						
							|  |  |  |   - thread safety undefined; | 
					
						
							|  |  |  |   - default file permissions (r+w) used, can't be over-ridden; | 
					
						
							|  |  |  |   - implemented in Python so comparatively slow, especially for large | 
					
						
							|  |  |  |     source files; | 
					
						
							|  |  |  |   - need sufficient free disk space to store the copy. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Behaviour:- | 
					
						
							|  |  |  |   - any exception should propagate to the caller; | 
					
						
							|  |  |  |   - want target to be an exact copy of the source, so use binary mode; | 
					
						
							|  |  |  |   - returns None, same as os.link() which is implemented in posixmodule.c; | 
					
						
							|  |  |  |   - target removed in the event of a failure where possible; | 
					
						
							|  |  |  |   - given the motivation to write this emulation came from trying to | 
					
						
							|  |  |  |     support a Unix resource lock implementation, where minimal overhead | 
					
						
							|  |  |  |     during creation of the target is desirable and the files are small, | 
					
						
							|  |  |  |     we read a source block before attempting to create the target so that | 
					
						
							|  |  |  |     we're ready to immediately write some data into it. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import errno | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __all__ = ['link'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def link(source, target): | 
					
						
							|  |  |  |     """link(source, target) -> None
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Attempt to hard link the source file to the target file name. | 
					
						
							|  |  |  |     On OS/2, this creates a complete copy of the source file. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s = os.open(source, os.O_RDONLY | os.O_BINARY) | 
					
						
							|  |  |  |     if os.isatty(s): | 
					
						
							| 
									
										
										
										
											2007-08-23 00:01:55 +00:00
										 |  |  |         raise OSError(errno.EXDEV, 'Cross-device link') | 
					
						
							| 
									
										
										
										
											2003-12-02 12:31:09 +00:00
										 |  |  |     data = os.read(s, 1024) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         t = os.open(target, os.O_WRONLY | os.O_BINARY | os.O_CREAT | os.O_EXCL) | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         os.close(s) | 
					
						
							|  |  |  |         raise | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         while data: | 
					
						
							|  |  |  |             os.write(t, data) | 
					
						
							|  |  |  |             data = os.read(s, 1024) | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         os.close(s) | 
					
						
							|  |  |  |         os.close(t) | 
					
						
							|  |  |  |         os.unlink(target) | 
					
						
							|  |  |  |         raise | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     os.close(s) | 
					
						
							|  |  |  |     os.close(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     import sys | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         link(sys.argv[1], sys.argv[2]) | 
					
						
							|  |  |  |     except IndexError: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |         print('Usage: emx_link <source> <target>') | 
					
						
							| 
									
										
										
										
											2003-12-02 12:31:09 +00:00
										 |  |  |     except OSError: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |         print('emx_link: %s' % str(sys.exc_info()[1])) |