|
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // POSIX systems calls implemented over EPOC32 |
|
15 // |
|
16 // |
|
17 |
|
18 #include "SYSIF.H" |
|
19 #include <unistd.h> |
|
20 #include <errno.h> |
|
21 #include "LPOSIX.H" |
|
22 #include <utf.h> |
|
23 #include <networking/dnd_err.h> |
|
24 |
|
25 GLDEF_C TInt GetFullPath(TParse& aParse, const TText16* upath, RFs& aSession, TDes* aFileName) |
|
26 // |
|
27 // Parse a path of the form "[C:][\]AAA\..\.\BBB\xxx" where: |
|
28 // . indicates the current directory |
|
29 // .. indicates move to the parent directory |
|
30 // An optional "\" at the start of the path indicates the path is not relative to the current path, |
|
31 // and is implied if the drive specifier is present |
|
32 // If aFileName is non-NULL then the final component is a filename and should be copied into |
|
33 // the aFileName descriptor. |
|
34 // |
|
35 { |
|
36 |
|
37 TInt r; |
|
38 TBuf<3> drive; |
|
39 TFileName nextBit; |
|
40 TText16 c=*upath; |
|
41 |
|
42 if (c && upath[1]==KDriveDelimiter) |
|
43 { |
|
44 // drive name specified |
|
45 if (c==L'?') |
|
46 drive.Zero(); // use "?:" to mean scan across drives |
|
47 else |
|
48 { |
|
49 drive.Copy(TPtrC16(upath, 2)); |
|
50 drive.UpperCase(); |
|
51 } |
|
52 upath+=2; |
|
53 drive.Append(TChar(KPathDelimiter)); // enforce absoluteness |
|
54 } |
|
55 else |
|
56 { |
|
57 // no leading drive specifier |
|
58 drive.Zero(); |
|
59 if (c==KPathDelimiter||c==L'/') |
|
60 { |
|
61 upath+=1; |
|
62 drive.Append(TChar(KPathDelimiter)); |
|
63 } |
|
64 } |
|
65 r = aSession.Parse(drive, aParse); |
|
66 |
|
67 // upath now looks like a relative pathname, to be added onto |
|
68 // aParse a directory at a time. Note that '/' is not allowed in |
|
69 // EPOC32 file or directory names, so treat it as an alternative separator |
|
70 |
|
71 c=*upath; |
|
72 while (c && (r==KErrNone)) |
|
73 { |
|
74 const TText16* ustart=upath; |
|
75 do |
|
76 c=*upath++; |
|
77 while (c && c!=KPathDelimiter && c!=L'/'); |
|
78 |
|
79 TInt len=(upath-ustart)-1; // excludes delimiter |
|
80 if (len==0) |
|
81 continue; |
|
82 if (ustart[0]==L'.') |
|
83 { |
|
84 if (len==1) |
|
85 continue; // directory . ignored |
|
86 if (len==2 && ustart[1]==L'.') |
|
87 { |
|
88 // directory .. |
|
89 (void) aParse.PopDir(); // just stick at root dir, no errors |
|
90 continue; |
|
91 } |
|
92 } |
|
93 if (len>=KMaxFileName) |
|
94 return ENAMETOOLONG; |
|
95 if (c==L'\0' && aFileName!=NULL) |
|
96 { |
|
97 // it's the trailing filename |
|
98 aFileName->Copy(TPtrC16(ustart, len)); |
|
99 break; |
|
100 } |
|
101 else |
|
102 { |
|
103 // it's a component of the accumulating path |
|
104 nextBit.Copy(TPtrC16(ustart, len)); |
|
105 r = aParse.AddDir(nextBit); |
|
106 } |
|
107 } |
|
108 return(r); |
|
109 } |
|
110 |
|
111 |
|
112 GLDEF_C TInt GetFullFile(TFileName& aName, const TText16* upath, RFs& aSession) |
|
113 // Use GetFullPath to establish the pathname, then add the filename onto the end |
|
114 { |
|
115 TParse path; |
|
116 TInt err = GetFullPath(path,upath,aSession,&aName); |
|
117 if (err!=KErrNone) |
|
118 return err; |
|
119 // Wildcard drive letter for searching across drives |
|
120 if (upath[0]==L'?' && upath[1]==L':') |
|
121 { |
|
122 TFindFile search(aSession); |
|
123 err=search.FindByDir(aName,path.Path()); |
|
124 if (!err) |
|
125 { |
|
126 aName=search.File(); |
|
127 return KErrNone; |
|
128 } |
|
129 } |
|
130 err = path.SetNoWild(path.DriveAndPath(),NULL,&aName); |
|
131 if (!err) |
|
132 aName = path.FullName(); |
|
133 return err; |
|
134 } |
|
135 |
|
136 |
|
137 // Set errno from an E32STD.H error code or a STDLIB errno value |
|
138 |
|
139 static const TUint8 EPOCtoERRNO[43] = { |
|
140 ENOENT, // KErrNotFound=(-1); |
|
141 0, // KErrGeneral=(-2); |
|
142 EINTR, // KErrCancel=(-3); |
|
143 ENOMEM, // KErrNoMemory=(-4); |
|
144 ENOSYS, // KErrNotSupported=(-5); |
|
145 EINVAL, // KErrArgument=(-6); |
|
146 0, // KErrTotalLossOfPrecision=(-7); |
|
147 0, // KErrBadHandle=(-8); |
|
148 ERANGE, // KErrOverflow=(-9); |
|
149 ERANGE, // KErrUnderflow=(-10); |
|
150 EEXIST, // KErrAlreadyExists=(-11); |
|
151 ENOENT, // KErrPathNotFound=(-12); |
|
152 EPIPE, // KErrDied=(-13); |
|
153 EACCES, // KErrInUse=(-14); |
|
154 EPIPE, // KErrServerTerminated=(-15); |
|
155 EBUSY, // KErrServerBusy=(-16); |
|
156 0, // KErrCompletion=(-17); |
|
157 0, // KErrNotReady=(-18); |
|
158 0, // KErrUnknown=(-19); |
|
159 0, // KErrCorrupt=(-20); |
|
160 EACCES, // KErrAccessDenied=(-21); |
|
161 EACCES, // KErrLocked=(-22); |
|
162 0, // KErrWrite=(-23); |
|
163 ENODEV, // KErrDisMounted=(-24); |
|
164 EPIPE, // KErrEof=(-25); |
|
165 ENOSPC, // KErrDiskFull=(-26); |
|
166 0, // KErrBadDriver=(-27); |
|
167 EINVAL, // KErrBadName=(-28); |
|
168 ECOMM, // KErrCommsLineFail=(-29); |
|
169 ECOMM, // KErrCommsFrame=(-30); |
|
170 ECOMM, // KErrCommsOverrun=(-31); |
|
171 ECOMM, // KErrCommsParity=(-32); |
|
172 ETIMEDOUT, // KErrTimedOut=(-33); |
|
173 ECONNREFUSED, // KErrCouldNotConnect=(-34); |
|
174 0, // KErrCouldNotDisconnect=(-35); |
|
175 EPIPE, // KErrDisconnected=(-36); |
|
176 0, // KErrBadLibraryEntryPoint=(-37); |
|
177 0, // KErrBadDescriptor=(-38); |
|
178 0, // KErrAbort=(-39); |
|
179 0, // KErrTooBig=(-40); |
|
180 EDOM, // KErrDivideByZero=(-41); |
|
181 EDOM, // KErrBadPower=(-42); |
|
182 ENOSPC // KErrDirFull=(-43); |
|
183 }; |
|
184 |
|
185 |
|
186 EXPORT_C int MapError(TInt err, int& anErrno) |
|
187 { |
|
188 if (err==0) |
|
189 return err; // i.e. return 0 without changing errno |
|
190 TInt ret=err; |
|
191 if (err<KErrNone && err>=KErrDirFull) |
|
192 { |
|
193 ret=EPOCtoERRNO[-1-err]; |
|
194 if (ret==0) |
|
195 ret=err; // no sensible translation |
|
196 } |
|
197 else if ((err == KErrDndNameNotFound) || (err == KErrDndAddrNotFound)) |
|
198 // KErrDndNameNotFound Returned when no data found for GetByName |
|
199 // KErrDndAddrNotFound Returned when no data found for GetByAddr |
|
200 { |
|
201 ret=ENOENT; |
|
202 } |
|
203 anErrno=ret; // KErr* values are negative, so will be distinct anyway |
|
204 return -1; |
|
205 } |
|
206 |
|
207 |
|
208 |
|
209 // Directory enumeration |
|
210 |
|
211 NONSHARABLE_STRUCT(__EPOC32_WDIR) : public CBase // aka "class __EPOC32_WDIR with everything public" |
|
212 { |
|
213 public: |
|
214 __EPOC32_WDIR(struct _reent* aContext) : iContext(aContext) {} |
|
215 ~__EPOC32_WDIR(); |
|
216 |
|
217 TInt Open(); |
|
218 TInt Open(const TDesC& aPath); |
|
219 TInt Open(const wchar_t *_path); |
|
220 |
|
221 virtual TInt UpdateNarrow(); |
|
222 struct _reent *iContext; |
|
223 HBufC* iPath; |
|
224 CDir* iEntries; |
|
225 TInt iIndex; // counting down, 0 means "finished" |
|
226 struct wdirent iCurrent; |
|
227 TBuf16<KMaxFileName> iCurrentName; |
|
228 }; |
|
229 |
|
230 TInt __EPOC32_WDIR::UpdateNarrow() |
|
231 { |
|
232 return -1; //this is not supported. |
|
233 } |
|
234 |
|
235 |
|
236 NONSHARABLE_STRUCT(__EPOC32_DIR) : public __EPOC32_WDIR |
|
237 { |
|
238 public: |
|
239 __EPOC32_DIR(struct _reent* aContext) : __EPOC32_WDIR(aContext) {} |
|
240 ~__EPOC32_DIR() {} |
|
241 |
|
242 virtual TInt UpdateNarrow(); |
|
243 struct dirent iCurrentNarrow; |
|
244 TBuf8<KMaxFileName> iCurrentNarrowName; |
|
245 }; |
|
246 |
|
247 |
|
248 TInt __EPOC32_DIR::UpdateNarrow() |
|
249 { |
|
250 //update the narrow one |
|
251 |
|
252 TInt ret = CnvUtfConverter::ConvertFromUnicodeToUtf8(iCurrentNarrowName, iCurrentName); |
|
253 if (ret >= 0) |
|
254 { |
|
255 iCurrentNarrow.d_namlen=(short)iCurrentNarrowName.Length(); |
|
256 iCurrentNarrow.d_name = (char*)iCurrentNarrowName.PtrZ(); |
|
257 } |
|
258 return ret; |
|
259 } |
|
260 |
|
261 |
|
262 __EPOC32_WDIR::~__EPOC32_WDIR() |
|
263 { |
|
264 delete iPath; |
|
265 delete iEntries; |
|
266 } |
|
267 |
|
268 TInt __EPOC32_WDIR::Open(const wchar_t *_path) |
|
269 { |
|
270 MSystemInterface& sysIf=Interface(iContext); |
|
271 TParse name; |
|
272 TInt err = sysIf.ResolvePath(name,_path,NULL); |
|
273 if (!err) |
|
274 err = Open(name.DriveAndPath()); |
|
275 if (err) |
|
276 MapError(err,iContext->_errno); |
|
277 return err; |
|
278 } |
|
279 |
|
280 TInt __EPOC32_WDIR::Open(const TDesC& aPath) |
|
281 { |
|
282 delete iPath; |
|
283 iPath=aPath.Alloc(); //allocate space for a hbufc and initialise it to the TDesC contents |
|
284 return Open(); |
|
285 } |
|
286 |
|
287 TInt __EPOC32_WDIR::Open() |
|
288 { |
|
289 delete iEntries; |
|
290 iEntries=0; |
|
291 iIndex=-1; |
|
292 if (iPath==0) |
|
293 return ENOMEM; |
|
294 RFs session; |
|
295 TInt err=session.Connect(); |
|
296 if (err) |
|
297 return err; |
|
298 err=session.GetDir(*iPath,KEntryAttMaskSupported,ESortByName+EDescending,iEntries); |
|
299 session.Close(); |
|
300 if (!err) |
|
301 iIndex=iEntries->Count(); |
|
302 return err; |
|
303 } |
|
304 |
|
305 extern "C" { |
|
306 |
|
307 /** |
|
308 Resets the position to the beginning of the directory. |
|
309 @param dp directory |
|
310 */ |
|
311 EXPORT_C void wrewinddir (WDIR *dp) |
|
312 { |
|
313 if (dp==0) |
|
314 return; |
|
315 (void) dp->Open(); // POSIX doesn't allow for rewind failing |
|
316 } |
|
317 |
|
318 /** |
|
319 Closes the directory. |
|
320 @param dp directory to close. |
|
321 */ |
|
322 EXPORT_C int wclosedir (WDIR *dp) |
|
323 { |
|
324 delete dp; |
|
325 return 0; |
|
326 } |
|
327 |
|
328 /** |
|
329 Opens a directory. |
|
330 @return a pointer to the dir object. |
|
331 This object describes the directory |
|
332 and is used in subsequent operations on the directory |
|
333 If error, returns NULL. |
|
334 @param _path path to the directory to be opened. |
|
335 */ |
|
336 EXPORT_C DIR *opendir (const char *_path) |
|
337 { |
|
338 return _opendir_r(_REENT,_path); |
|
339 } |
|
340 |
|
341 /** A wide-character version of opendir() |
|
342 */ |
|
343 EXPORT_C WDIR *wopendir (const wchar_t *_path) |
|
344 { |
|
345 return _wopendir_r(_REENT,_path); |
|
346 } |
|
347 |
|
348 /** A reentrant version of opendir(). |
|
349 */ |
|
350 EXPORT_C DIR *_opendir_r (struct _reent *r, const char *_path) |
|
351 { |
|
352 |
|
353 wchar_t _widepath[KMaxFileName+1]; |
|
354 |
|
355 if (mbstowcs(_widepath, _path, KMaxFileName) < 0) |
|
356 { |
|
357 MapError(EILSEQ,r->_errno); |
|
358 return 0; |
|
359 } |
|
360 //coverity[alloc_fn] |
|
361 //coverity[assign] |
|
362 |
|
363 DIR* dp = new __EPOC32_DIR(r); |
|
364 if (dp==0) |
|
365 { |
|
366 r->_errno=ENOMEM; |
|
367 return 0; |
|
368 } |
|
369 |
|
370 //coverity[leave_without_push] |
|
371 |
|
372 TInt err = dp->Open(_widepath); |
|
373 if (err) |
|
374 { |
|
375 delete dp; |
|
376 return 0; |
|
377 } |
|
378 return dp; |
|
379 } |
|
380 |
|
381 /** A reentrant version of wopendir(). |
|
382 */ |
|
383 EXPORT_C WDIR *_wopendir_r (struct _reent *r, const wchar_t *_path) |
|
384 { |
|
385 |
|
386 //coverity[alloc_fn] |
|
387 //coverity[assign] |
|
388 |
|
389 WDIR* dp = new __EPOC32_WDIR(r); |
|
390 if (dp==0) |
|
391 { |
|
392 r->_errno=ENOMEM; |
|
393 return 0; |
|
394 } |
|
395 //coverity[leave_without_push] |
|
396 |
|
397 TInt err = dp->Open(_path); |
|
398 if (err) |
|
399 { |
|
400 delete dp; |
|
401 return 0; |
|
402 } |
|
403 return dp; |
|
404 } |
|
405 |
|
406 /** |
|
407 Sets the index position of the directory stream specified by dp |
|
408 to the position specified by index. |
|
409 */ |
|
410 EXPORT_C void wseekdir(WDIR *dp,off_t index) |
|
411 { |
|
412 dp->iIndex=index; |
|
413 } |
|
414 |
|
415 EXPORT_C off_t wtelldir(const WDIR *dp) |
|
416 { |
|
417 return dp->iIndex; |
|
418 } |
|
419 |
|
420 EXPORT_C struct wdirent *wreaddir (WDIR *dp) |
|
421 { |
|
422 if (dp->iIndex<=0) |
|
423 return 0; |
|
424 struct wdirent *ep=&dp->iCurrent; |
|
425 const TEntry& entry=(*dp->iEntries)[--(dp->iIndex)]; |
|
426 // in practice, these files must have been created as "X:\something", so they |
|
427 // can't really be longer than KMaxFileName-3 |
|
428 dp->iCurrentName.Copy(entry.iName); |
|
429 dp->iCurrentName.ZeroTerminate(); |
|
430 ep->d_namlen=(short)dp->iCurrentName.Length(); |
|
431 ep->d_name=(wchar_t*)dp->iCurrentName.PtrZ(); |
|
432 return ep; |
|
433 } |
|
434 |
|
435 /** |
|
436 Returns a pointer to a dirent structure representing |
|
437 the next directory entry in the directory stream pointed to be dir. |
|
438 It returns NULL on reaching the end-of-file or if an error occurred. |
|
439 @return a pointer to a dirent structure, or NULL if an error occurs |
|
440 or end-of-file is reached. |
|
441 @param dp Points to the directory stream of the directory. |
|
442 */ |
|
443 EXPORT_C struct dirent *readdir (DIR *dp) |
|
444 { |
|
445 return _readdir_r(_REENT, dp); |
|
446 } |
|
447 |
|
448 /** A reentrant version of readdir(). |
|
449 */ |
|
450 EXPORT_C struct dirent *_readdir_r (struct _reent *r, DIR *dp) |
|
451 { |
|
452 if (wreaddir(dp)) |
|
453 { |
|
454 if (dp->UpdateNarrow()>=0) |
|
455 return &dp->iCurrentNarrow; |
|
456 else |
|
457 r->_errno = EINVAL; |
|
458 } |
|
459 |
|
460 return 0; |
|
461 } |
|
462 |
|
463 /** |
|
464 Sets the position (associated with the directory stream that dirp points to) |
|
465 to the beginning of the directory. |
|
466 Additionally, it causes the directory stream to refer to the current state of |
|
467 the corresponding directory. |
|
468 @param dp Points to the directory stream of the directory to rewind. |
|
469 */ |
|
470 EXPORT_C void rewinddir (DIR *dp) |
|
471 { |
|
472 wrewinddir(dp); |
|
473 } |
|
474 |
|
475 /** |
|
476 closes the directory stream that dirp refers to. |
|
477 The memory associated with the directory stream is released. |
|
478 When this function returns, the value of dirp no longer point to |
|
479 an accessible object of type DIR |
|
480 @return a value of zero. On failure, it returns -1 |
|
481 @param dp Is the directory pointer to close (from opendir()). |
|
482 */ |
|
483 EXPORT_C int closedir (DIR *dp) |
|
484 { |
|
485 return wclosedir(dp); |
|
486 } |
|
487 |
|
488 /** |
|
489 sets the position of the next readdir() operation on the directory |
|
490 stream specified by dp to the position specified by index |
|
491 @param dp Points to the directory stream of the directory |
|
492 @param index |
|
493 */ |
|
494 EXPORT_C void seekdir(DIR *dp,off_t index) |
|
495 { |
|
496 wseekdir(dp,index); |
|
497 } |
|
498 |
|
499 /** |
|
500 Returns the current location associated with the directory stream dir. |
|
501 @return the current location in the directory stream or -1 if an error occurs. |
|
502 @param dp Points to the directory stream of the directory |
|
503 */ |
|
504 EXPORT_C off_t telldir(const DIR *dp) |
|
505 { |
|
506 return wtelldir(dp); |
|
507 } |
|
508 |
|
509 } // extern "C" |