]> err.no Git - sope/blob - libFoundation/Foundation/NSPosixFileDescriptor.m
Drop apache 1 build-dependency
[sope] / libFoundation / Foundation / NSPosixFileDescriptor.m
1 /* 
2    NSPosixFileDescriptor.m
3
4    Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
5    All rights reserved.
6
7    Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
8
9    This file is part of libFoundation.
10
11    Permission to use, copy, modify, and distribute this software and its
12    documentation for any purpose and without fee is hereby granted, provided
13    that the above copyright notice appear in all copies and that both that
14    copyright notice and this permission notice appear in supporting
15    documentation.
16
17    We disclaim all warranties with regard to this software, including all
18    implied warranties of merchantability and fitness, in no event shall
19    we be liable for any special, indirect or consequential damages or any
20    damages whatsoever resulting from loss of use, data or profits, whether in
21    an action of contract, negligence or other tortious action, arising out of
22    or in connection with the use or performance of this software.
23 */
24
25 #include <errno.h>
26 #include <stdio.h>
27
28 #if defined(__MINGW32__)
29 # include <windows.h>
30 # include <winsock.h>
31 #else
32 # include <sys/ioctl.h>
33 #endif
34
35 #include <Foundation/common.h>
36 #include <Foundation/NSString.h>
37 #include <Foundation/NSArray.h>
38 #include <Foundation/NSData.h>
39 #include <Foundation/NSException.h>
40 #include <Foundation/NSPosixFileDescriptor.h>
41 #include <Foundation/NSRunLoop.h>
42 #include <Foundation/NSPathUtilities.h>
43 #include <Foundation/exceptions/GeneralExceptions.h>
44
45 #include "NSMappedData.h"
46
47 @implementation NSPosixFileDescriptor
48
49 // Getting a standard NSPosixFileDescriptor
50
51 static NSPosixFileDescriptor* descriptorForStandardInput = nil;
52 static NSPosixFileDescriptor* descriptorForStandardOutput = nil;
53 static NSPosixFileDescriptor* descriptorForStandardError = nil;
54
55 + (void)initialize
56 {
57     if (!descriptorForStandardInput)
58         descriptorForStandardInput = [[self alloc] 
59             initWithFileDescriptor:fileno(stdin)];
60     if (!descriptorForStandardOutput)
61         descriptorForStandardOutput = [[self alloc] 
62             initWithFileDescriptor:fileno(stdout)];
63     if (!descriptorForStandardError)
64         descriptorForStandardError = [[self alloc] 
65             initWithFileDescriptor:fileno(stderr)];
66 }
67
68 + (id)descriptorWithStandardInput
69 {
70     return descriptorForStandardInput;
71 }
72
73 + (id)descriptorWithStandardOutput
74 {
75     return descriptorForStandardOutput;
76 }
77
78 + (id)descriptorWithStandardError
79 {
80     return descriptorForStandardError;
81 }
82
83 // Initialize
84
85 - (id)initWithFileDescriptor:(int)fileDescriptor
86 {
87     fd = fileDescriptor;
88     owned = NO;
89     return self;
90 }
91
92 - (id)initWithCStringPath:(const char*)aPath flags:(int)someFlags 
93   createMode:(int)someMode
94 {
95     fd = open(aPath, someFlags, someMode);
96     if (fd == -1) {
97 #if DEBUG
98         NSLog(@"%s: couldn't open file '%s': %s", __PRETTY_FUNCTION__,
99               aPath, strerror(errno));
100 #endif
101         (void)RELEASE(self);
102         return nil;
103     }
104     owned = YES;
105     return self;
106 }
107
108 - (id)initWithPath:(NSString*)aPath
109 {
110     return [self initWithCStringPath:[aPath fileSystemRepresentation] 
111             flags:O_RDONLY createMode:0];
112 }
113
114 - (id)initWithPath:(NSString*)aPath flags:(int)someFlags
115 {
116     return [self initWithCStringPath:[aPath fileSystemRepresentation] 
117             flags:someFlags createMode:0];
118 }
119
120 - (id)initWithPath:(NSString*)aPath flags:(int)someFlags 
121   createMode:(int)someMode
122 {
123     return [self initWithCStringPath:[aPath fileSystemRepresentation] 
124             flags:someFlags createMode:someMode];
125 }
126
127 - (void)dealloc
128 {
129   if (owned)
130     close (fd);
131   [super dealloc];
132 }
133
134 // Get FD
135
136 - (int)fileDescriptor
137 {
138     return self->fd;
139 }
140
141 // Read
142
143 - (NSData *)readEntireFile
144 {
145     NSRange range;
146     off_t   ret;
147     
148     if ((ret = lseek(fd, 0, SEEK_END)) == -1) {
149         /* lseek failed */
150         [[[PosixFileOperationException alloc]
151             initWithFormat:@"could not lseek to end"] raise];
152     }
153     range.location = 0;
154     range.length   = ret;
155     return [self readFileRange:range]; 
156 }
157
158 - (NSData *)readRestOfFile
159 {
160     NSRange range;
161     off_t   ret;
162
163     if ((ret = lseek(fd, 0, SEEK_CUR)) == -1) {
164         /* lseek failed */
165         [[[PosixFileOperationException alloc]
166             initWithFormat:@"could not lseek to cur"] raise];
167     }
168     else
169         range.location = ret;
170
171     if ((ret = lseek(fd, 0, SEEK_END)) == -1) {
172         /* lseek failed */
173         [[[PosixFileOperationException alloc]
174             initWithFormat:@"could not lseek to end"] raise];
175     }
176     else
177         range.location = ret - range.location;
178     
179     return [self readFileRange:range];
180 }
181
182 - (NSData *)readFileRange:(NSRange)range
183 {       
184     void  *bytes;
185     off_t ret;
186     
187     bytes = MallocAtomic(range.length);
188     
189     if ((ret = lseek(fd, range.location, SEEK_SET)) == -1) {
190         /* lseek failed */
191         [[[PosixFileOperationException alloc]
192             initWithFormat:@"could not lseek set"] raise];
193     }
194     
195     if (read(fd, bytes, range.length) != (int)range.length) {
196         lfFree(bytes);
197         [[[PosixFileOperationException alloc]
198             initWithFormat:@"could not read %d bytes", range.length] raise];
199     }
200     
201     return AUTORELEASE([[NSData alloc]
202                            initWithBytesNoCopy:bytes length:range.length]);
203 }
204
205 - (void)readBytes:(void *)bytes range:(NSRange)range
206 {
207     off_t ret;
208     
209     if ((ret = lseek(fd, range.location, SEEK_SET)) == -1) {
210         /* lseek failed */
211         [[[PosixFileOperationException alloc]
212             initWithFormat:@"could not lseek set"] raise];
213     }
214     
215     if (read(fd, bytes, range.length) != (int)range.length)
216         [[[PosixFileOperationException alloc]
217             initWithFormat:@"could not read %d bytes", range.length] raise];
218 }
219
220 - (NSData *)readFileLength:(long)length
221 {
222     NSRange range;
223     off_t   ret;
224 #if DEBUG
225     NSAssert(length >= 0, @"invalid length %i", length);
226 #endif
227
228     if ((ret = lseek(fd, 0, SEEK_CUR)) == -1) {
229         /* lseek failed */
230         [[[PosixFileOperationException alloc]
231             initWithFormat:@"could not lseek cur"] raise];
232     }
233     range.location = ret;
234     range.length   = length;
235     
236     return [self readFileRange:range];
237 }
238
239 // Write
240
241 - (void)writeData:(NSData*)aData
242 {
243     NSRange range = {0, [aData length]};    
244     [self writeData:aData range:range];
245 }
246
247 - (void)writeData:(NSData*)aData range:(NSRange)range
248 {
249     char *bytes;
250     
251     if (range.location + range.length > [aData length]) {
252         [[[RangeException alloc]
253                 initWithReason:@"invalid range in NSData" size:[aData length] 
254                     index:range.location+range.length] raise];
255     }
256     
257     bytes = (char*)[aData bytes] + range.location;
258     if (write(fd, bytes, range.length) != (int)range.length) {
259         [[[PosixFileOperationException alloc]
260             initWithFormat:@"could not write %d bytes", range.length] raise];
261     }
262 }
263
264 - (void)writeString:(NSString*)string
265 {
266     NSRange range = {0, [string cStringLength]};    
267     [self writeString:string range:range];
268 }
269
270 - (void)writeString:(NSString*)string range:(NSRange)range
271 {
272     unsigned len = range.length;
273     char* bytes;
274     
275     if (range.location + range.length > [string cStringLength])
276         [[[RangeException alloc]
277                 initWithReason:@"invalid range in NSString"
278                     size:[string cStringLength] 
279                     index:range.location + range.length] raise];
280     
281     bytes = (char*)[string cString] + range.location;
282     while (len > 0) {
283         int res = write(fd, bytes, len);
284
285         if (res == -1) {
286             [[[PosixFileOperationException alloc]
287                       initWithFormat:@"could not write %d bytes", len] raise];
288         }
289         len -= res;
290         bytes += res;
291     }
292 }
293
294 // Seek
295
296 - (int unsigned)fileLength
297 {
298     off_t cur, len, ret;
299     
300     if ((cur = lseek(fd, 0, SEEK_CUR)) == -1) {
301         /* lseek failed */
302         [[[PosixFileOperationException alloc]
303             initWithFormat:@"could not lseek to cur"] raise];
304     }
305     if ((len = lseek(fd, 0, SEEK_END)) == -1) {
306         /* lseek failed */
307         [[[PosixFileOperationException alloc]
308             initWithFormat:@"could not lseek to end"] raise];
309     }
310     
311     if ((ret = lseek(fd, cur, SEEK_SET)) == -1) {
312         /* lseek failed */
313         [[[PosixFileOperationException alloc]
314             initWithFormat:@"could not lseek set"] raise];
315     }
316     return len;
317 }
318
319 - (int unsigned)filePosition
320 {
321     off_t ret;
322
323     if ((ret = lseek(fd, 0, SEEK_CUR)) == -1) {
324         /* lseek failed */
325         [[[PosixFileOperationException alloc]
326             initWithFormat:@"could not lseek to cur"] raise];
327     }
328     
329     return ret;
330 }
331
332 - (void)seekToEnd
333 {
334     lseek(fd, 0, SEEK_END);
335 }
336
337 - (void)seekToPosition:(long)aPosition
338 {
339     lseek(fd, aPosition, SEEK_SET);
340 }
341
342 - (void)truncateAtPosition:(long)aPosition
343 {
344     lseek(fd, aPosition, SEEK_SET);
345 #if defined(__MINGW32__)
346     if (_chsize(fd, aPosition) != 0)
347 #else
348     if (ftruncate(fd, aPosition) != 0)
349 #endif
350         [[[PosixFileOperationException alloc]
351             initWithFormat:@"could not truncate file"] raise];
352 }
353
354 // Mapping files to memory
355
356 - (NSData *)mapFileRange:(NSRange)range
357 {
358     return AUTORELEASE([[NSMappedData alloc]
359                            initWithPosixFileDescriptor:self range:range]);
360 }
361
362 - (void)synchronizeFile
363 {
364 #if HAVE_FSYNC
365     if (fsync(fd) != 0)
366         [[[PosixFileOperationException alloc]
367             initWithFormat:@"could not sync file"] raise];
368 #endif
369 }
370
371 // Monitoring file descriptors
372
373 - (void)ceaseMonitoringFileActivity
374 {
375     NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
376
377     fileActivity = 0;
378     [runLoop removePosixFileDescriptor:self forMode:[runLoop currentMode]];
379 }
380
381 - (NSPosixFileActivities)fileActivity
382 {
383     return fileActivity;
384 }
385
386 - (void)monitorFileActivity:(NSPosixFileActivities)activity
387 {
388     NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
389
390     fileActivity |= activity;
391     [runLoop addPosixFileDescriptor:self forMode:[runLoop currentMode]];
392 }
393
394 - (void)monitorActivity:(NSPosixFileActivities)activity delegate:(id)anObject
395 {
396     [self setDelegate:anObject];
397     [self monitorFileActivity:activity];
398 }
399
400 // File descriptor delegate
401
402 - (id)delegate
403 {
404     return delegate;
405 }
406
407 - (void)setDelegate:(id)aDelegate
408 {
409     delegate = aDelegate;
410 }
411
412 @end /* NSPosixFileDescriptor */
413
414 /*
415   Local Variables:
416   c-basic-offset: 4
417   tab-width: 8
418   End:
419 */