1 // Copyright (c) 1999-2018 David Muse
2 // See the COPYING file for more information
3
4
5 #include <rudiments/file.h>
6 #include <rudiments/userentry.h>
7 #include <rudiments/groupentry.h>
8 #include <rudiments/charstring.h>
9 #include <rudiments/bytestring.h>
10 #include <rudiments/error.h>
11 #include <rudiments/stringbuffer.h>
12 #include <rudiments/permissions.h>
13 #include <rudiments/directory.h>
14 #include <rudiments/stdio.h>
15 #ifndef RUDIMENTS_HAVE_BLKSIZE_T
16 #include <rudiments/filesystem.h>
17 #endif
18
19 #ifdef RUDIMENTS_HAVE_WINDOWS_H
20 #include <windows.h>
21 #endif
22
23 // for struct stat
24 #ifdef RUDIMENTS_HAVE_SYS_STAT_H
25 #include <sys/stat.h>
26 #endif
27
28 #if !defined(RUDIMENTS_HAVE_UTIMES_CONST_CHAR) && \
29 !defined(RUDIMENTS_HAVE_UTIMES_CHAR)
30 #include <rudiments/datetime.h>
31 #endif
32 #ifndef RUDIMENTS_HAVE_MKSTEMP
33 #include <rudiments/datetime.h>
34 #include <rudiments/randomnumber.h>
35 #include <rudiments/permissions.h>
36 #endif
37
38 #include <stdio.h>
39 #ifdef RUDIMENTS_HAVE_STDLIB_H
40 #include <stdlib.h>
41 #endif
42 #ifdef RUDIMENTS_HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #ifdef RUDIMENTS_HAVE_SYS_TIME_H
46 #include <sys/time.h>
47 #endif
48 #ifdef RUDIMENTS_HAVE_UTIME_H
49 #include <utime.h>
50 #endif
51 #ifdef RUDIMENTS_HAVE_IO_H
52 #undef _POSIX_
53 #include <io.h>
54 #endif
55 #ifdef RUDIMENTS_HAVE_ACLAPI_H
56 #include <aclapi.h>
57 #endif
58 #ifdef RUDIMENTS_HAVE_ACCCTRL_H
59 #include <accctrl.h>
60 #endif
61
62 // windows doesn't define these, but we need them
63 // internally to this file
64 #ifndef F_GETLK
65 #define F_GETLK 0
66 #endif
67 #ifndef F_SETLK
68 #define F_SETLK 1
69 #endif
70 #ifndef F_SETLKW
71 #define F_SETLKW 2
72 #endif
73 #ifndef _PC_LINK_MAX
74 #define _PC_LINK_MAX 0
75 #endif
76 #ifndef _PC_CHOWN_RESTRICTED
77 #define _PC_CHOWN_RESTRICTED 1
78 #endif
79 #ifndef F_OK
80 #define F_OK 0
81 #endif
82 #ifndef W_OK
83 #define W_OK 2
84 #endif
85 #ifndef R_OK
86 #define R_OK 4
87 #endif
88 #ifndef X_OK
89 // no such thing on windows, so we'll
90 // just set this to be the same as F_OK
91 #define X_OK 0
92 #endif
93
94 #ifdef RUDIMENTS_HAVE_UNDEFINED_FSYNC
95 extern "C" int fsync(int);
96 #endif
97
98 #ifdef RUDIMENTS_HAVE_UNDEFINED_FTRUNCATE
99 extern "C" int ftruncate(int,int);
100 #endif
101
102 class fileprivate {
103 friend class file;
104 private:
105 struct stat _st;
106 #if defined(RUDIMENTS_HAVE_GETFILETYPE)
107 DWORD _filetype;
108 #endif
109 #if defined(RUDIMENTS_HAVE_GETFILEINFORMATIONBYHANDLE)
110 uint64_t _inode;
111 #endif
112 #ifndef RUDIMENTS_HAVE_BLKSIZE_T
113 char *_name;
114 blksize_t _blocksize;
115 #endif
116 bool _getcurrentpropertiesonopen;
117 };
118
file()119 file::file() : filedescriptor() {
120 pvt=new fileprivate;
121 bytestring::zero(&pvt->_st,sizeof(pvt->_st));
122 #if defined(RUDIMENTS_HAVE_GETFILETYPE)
123 pvt->_filetype=0;
124 #endif
125 #if defined(RUDIMENTS_HAVE_GETFILEINFORMATIONBYHANDLE)
126 pvt->_inode=0;
127 #endif
128 #ifndef RUDIMENTS_HAVE_BLKSIZE_T
129 pvt->_name=NULL;
130 pvt->_blocksize=0;
131 #endif
132 pvt->_getcurrentpropertiesonopen=true;
133 type("file");
134 }
135
file(const file & f)136 file::file(const file &f) : filedescriptor(f) {
137 pvt=new fileprivate;
138 fileClone(f);
139 type("file");
140 }
141
operator =(const file & f)142 file &file::operator=(const file &f) {
143 if (this!=&f) {
144 filedescriptor::operator=(f);
145 fileClone(f);
146 }
147 return *this;
148 }
149
fileClone(const file & f)150 void file::fileClone(const file &f) {
151 pvt->_st=f.pvt->_st;
152 #if defined(RUDIMENTS_HAVE_GETFILETYPE)
153 pvt->_filetype=f.pvt->_filetype;
154 #endif
155 #if defined(RUDIMENTS_HAVE_GETFILEINFORMATIONBYHANDLE)
156 pvt->_inode=f.pvt->_inode;
157 #endif
158 #ifndef RUDIMENTS_HAVE_BLKSIZE_T
159 pvt->_name=charstring::duplicate(f.pvt->_name);
160 pvt->_blocksize=f.pvt->_blocksize;
161 #endif
162 pvt->_getcurrentpropertiesonopen=f.pvt->_getcurrentpropertiesonopen;
163 }
164
~file()165 file::~file() {
166
167 // set NOTE in ~threadmutex()
168
169 if (!pvt) {
170 return;
171 }
172
173 #ifndef RUDIMENTS_HAVE_BLKSIZE_T
174 if (pvt->_name) {
175 char *tmpname=pvt->_name;
176 pvt->_name=NULL;
177 delete[] tmpname;
178 }
179 #endif
180
181 fileprivate *tmppvt=pvt;
182 pvt=NULL;
183 delete tmppvt;
184 }
185
create(const char * name,mode_t perms)186 bool file::create(const char *name, mode_t perms) {
187 return open(name,O_CREAT|O_TRUNC|O_RDWR|O_BINARY,perms);
188 }
189
createFile(const char * name,mode_t perms)190 bool file::createFile(const char *name, mode_t perms) {
191 file fl;
192 return fl.create(name,perms);
193 }
194
lowLevelOpen(const char * name,int32_t flags,mode_t perms,bool useperms)195 bool file::lowLevelOpen(const char *name, int32_t flags,
196 mode_t perms, bool useperms) {
197
198 // don't allow create without perms
199 if (flags&O_CREAT && (!perms || !useperms)) {
200 error::setErrorNumber(EINVAL);
201 return false;
202 }
203
204 #ifndef RUDIMENTS_HAVE_BLKSIZE_T
205 delete[] pvt->_name;
206 pvt->_name=charstring::duplicate(name);
207 #endif
208
209 #ifdef RUDIMENTS_HAVE_CREATEFILE
210
211 // On Windows, when creating a file, in order to set permissions
212 // other than just owner read/write, the CreateFile method must
213 // be used rather than just plain _open.
214 // Also, on Windows, if you want to be able to set file
215 // ownership and permissions, you have to use CreateFile just to
216 // open the file so that the access mode can include WRITE_DAC
217 // and WRITE_OWNER, which are not set when using _open.
218
219 PSECURITY_DESCRIPTOR psd=NULL;
220 void *dacl=NULL;
221 PSECURITY_ATTRIBUTES psatt=NULL;
222
223 if (flags&O_CREAT) {
224
225 // create security descriptor
226 psd=(PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
227 SECURITY_DESCRIPTOR_MIN_LENGTH);
228 if (!InitializeSecurityDescriptor(psd,
229 SECURITY_DESCRIPTOR_REVISION)) {
230 fd(-1);
231 LocalFree(psd);
232 return false;
233 }
234 dacl=permissions::permOctalToDacl(perms,true);
235 if (!SetSecurityDescriptorDacl(psd,TRUE,
236 (PACL)dacl,FALSE)
237 #if _WIN32_WINNT>=0x0500
238 || !SetSecurityDescriptorControl(psd,
239 SE_DACL_PROTECTED,
240 SE_DACL_PROTECTED)
241 #endif
242 ) {
243 fd(-1);
244 LocalFree(dacl);
245 LocalFree(psd);
246 return false;
247 }
248
249 // create security attributes
250 SECURITY_ATTRIBUTES satt;
251 satt.nLength=sizeof(SECURITY_ATTRIBUTES);
252 satt.lpSecurityDescriptor=psd;
253 satt.bInheritHandle=TRUE;
254 psatt=&satt;
255 }
256
257 // Determine the access and share modes.
258 // O_RDONLY, O_WRONLY and O_RDWR are usually 0, 1 and 2.
259 // We can use & to test for O_WRONLY and O_RDWR but we can't
260 // effectively test for O_RDONLY at all, except by testing for
261 // the lack of the other two. It's easier to default to
262 // read-only and just update the access/share modes if we
263 // detect O_WRONLY/O_RDWR.
264 DWORD accessmode=GENERIC_READ|READ_CONTROL;
265 if (flags&O_WRONLY) {
266 accessmode=GENERIC_WRITE|DELETE|WRITE_DAC|WRITE_OWNER;
267 }
268 if (flags&O_RDWR) {
269 accessmode=GENERIC_WRITE|DELETE|WRITE_DAC|WRITE_OWNER|
270 GENERIC_READ|READ_CONTROL;
271 }
272
273 // determine the creation disposition
274 DWORD cdisp=0;
275 if (flags&O_CREAT) {
276 if (flags&O_EXCL) {
277 cdisp=CREATE_NEW;
278 } else {
279 // O_CREAT without O_EXCL should create the
280 // file if it doesn't exist but otherwise just
281 // open it normally.
282 // CREATE_ALWAYS creates the file if it doesn't
283 // exist, but otherwise "replaces" it - ie. it
284 // opens and truncates it.
285 // We need to open the file normally if it
286 // exists (OPEN_EXISTING) and otherwise create
287 // it (CREATE_ALWAYS).
288 // Unfortunately we can't do all of that
289 // atomically.
290 cdisp=(exists(name))?
291 OPEN_EXISTING:CREATE_ALWAYS;
292 }
293 } else {
294 cdisp=OPEN_EXISTING;
295 }
296
297 // determine the attrs
298 // FILE_FLAG_BACKUP_SEMANTICS must be used when opening a
299 // directory, for some reason
300 DWORD attrs=FILE_ATTRIBUTE_NORMAL;
301 DWORD fileattr=GetFileAttributes(name);
302 if (fileattr&FILE_ATTRIBUTE_DIRECTORY) {
303 attrs=FILE_FLAG_BACKUP_SEMANTICS;
304 }
305
306 // create/open the file
307 HANDLE fh=CreateFile(name,accessmode,
308 FILE_SHARE_DELETE|
309 FILE_SHARE_READ|
310 FILE_SHARE_WRITE,
311 #if _WIN32_WINNT>=0x0500
312 psatt,
313 #else
314 NULL,
315 #endif
316 cdisp,attrs,NULL);
317 LocalFree(psd);
318 LocalFree(dacl);
319
320 if (fh==INVALID_HANDLE_VALUE) {
321 fd(-1);
322
323 // handle file/directory not found
324 // FIXME: really there ought to be a generic
325 // Windows-Posix error mapping function call here
326 int32_t err=error::getNativeErrorNumber();
327 if (err==2 || err==3) {
328 error::setErrorNumber(ENOENT);
329 }
330
331 return false;
332 }
333
334 // get the file descriptor from the handle
335 fd(_open_osfhandle((long)fh,flags&~(O_CREAT|O_TRUNC)));
336
337 // truncate if necessary
338 if (flags&O_TRUNC) {
339 truncate();
340 }
341
342 // append if specified
343 if (flags&O_APPEND) {
344 setPositionRelativeToEnd(0);
345 }
346 #else
347
348 int32_t result;
349 error::clearError();
350 do {
351 if (useperms) {
352 #if defined(RUDIMENTS_HAVE__OPEN)
353 result=_open(name,flags,perms);
354 #elif defined(RUDIMENTS_HAVE_OPEN)
355 result=::open(name,flags,perms);
356 #else
357 #error no open or anything like it
358 #endif
359 } else {
360 #if defined(RUDIMENTS_HAVE__OPEN)
361 result=_open(name,flags);
362 #elif defined(RUDIMENTS_HAVE_OPEN)
363 result=::open(name,flags);
364 #else
365 #error no open or anything like it
366 #endif
367 }
368 } while (result==-1 && error::getErrorNumber()==EINTR);
369 fd(result);
370 #endif
371
372 return (fd()!=-1);
373 }
374
open(const char * name,int32_t flags)375 bool file::open(const char *name, int32_t flags) {
376 return (lowLevelOpen(name,flags,0,false) &&
377 ((pvt->_getcurrentpropertiesonopen)?
378 getCurrentProperties():true));
379 }
380
open(const char * name,int32_t flags,mode_t perms)381 bool file::open(const char *name, int32_t flags, mode_t perms) {
382 return (lowLevelOpen(name,flags,perms,true) &&
383 ((pvt->_getcurrentpropertiesonopen)?
384 getCurrentProperties():true));
385 }
386
getContents()387 char *file::getContents() {
388 if (fd()==-1) {
389 return NULL;
390 }
391 getCurrentProperties();
392 off64_t curpos=getCurrentPosition();
393 setPositionRelativeToBeginning(0);
394 char *contents=NULL;
395 if (pvt->_st.st_size) {
396 off64_t size=pvt->_st.st_size;
397 contents=new char[size+1];
398 contents[size]='\0';
399 if (size && read(contents,size)!=size) {
400 delete[] contents;
401 contents=NULL;
402 }
403 } else {
404 stringbuffer cts;
405 // FIXME: this is fine for url's but for actual files that
406 // we don't know the size of, we ought to use a more
407 // intelligent size.
408 char buffer[16*1024];
409 for (;;) {
410 ssize_t s=read(buffer,sizeof(buffer));
411 cts.append(buffer,s);
412 if (s<(ssize_t)sizeof(buffer)) {
413 contents=cts.detachString();
414 break;
415 }
416 }
417 }
418 setPositionRelativeToBeginning(curpos);
419 return contents;
420 }
421
getContents(const char * name)422 char *file::getContents(const char *name) {
423 file fl;
424 fl.open(name,O_RDONLY|O_BINARY);
425 char *contents=fl.getContents();
426 fl.close();
427 return contents;
428 }
429
getContents(unsigned char * buffer,size_t buffersize)430 ssize_t file::getContents(unsigned char *buffer, size_t buffersize) {
431 return read(buffer,buffersize);
432 }
433
getContents(const char * name,unsigned char * buffer,size_t buffersize)434 ssize_t file::getContents(const char *name, unsigned char *buffer,
435 size_t buffersize) {
436 file fl;
437 fl.open(name,O_RDONLY|O_BINARY);
438 ssize_t bytes=fl.getContents(buffer,buffersize);
439 fl.close();
440 return bytes;
441 }
442
443
tryLockFile(int16_t type) const444 bool file::tryLockFile(int16_t type) const {
445 return tryLockRegion(type,0,0);
446 }
447
lockFile(int16_t type) const448 bool file::lockFile(int16_t type) const {
449 return lockRegion(type,0,0);
450 }
451
checkLockFile(int16_t type,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const452 bool file::checkLockFile(int16_t type,
453 int16_t *conftype, int16_t *confwhence,
454 off64_t *confstart, off64_t *conflen) const {
455 return checkLockRegion(type,0,0,conftype,confwhence,confstart,conflen);
456 }
457
unlockFile() const458 bool file::unlockFile() const {
459 return unlockRegion(0,0);
460 }
461
tryLockRegion(int16_t type,off64_t start,off64_t len) const462 bool file::tryLockRegion(int16_t type, off64_t start, off64_t len) const {
463 return lock(F_SETLK,type,SEEK_SET,start,len);
464 }
465
lockRegion(int16_t type,off64_t start,off64_t len) const466 bool file::lockRegion(int16_t type, off64_t start, off64_t len) const {
467 return lock(F_SETLKW,type,SEEK_SET,start,len);
468 }
469
checkLockRegion(int16_t type,off64_t start,off64_t len,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const470 bool file::checkLockRegion(int16_t type, off64_t start, off64_t len,
471 int16_t *conftype, int16_t *confwhence,
472 off64_t *confstart, off64_t *conflen) const {
473 return checkLock(type,SEEK_SET,start,len,
474 conftype,confwhence,confstart,conflen);
475 }
476
unlockRegion(off64_t start,off64_t len) const477 bool file::unlockRegion(off64_t start, off64_t len) const {
478 return unlock(SEEK_SET,start,len);
479 }
480
tryLockFromCurrent(int16_t type,off64_t len) const481 bool file::tryLockFromCurrent(int16_t type, off64_t len) const {
482 return tryLockFromCurrent(type,0,len);
483 }
484
tryLockFromCurrent(int16_t type,off64_t start,off64_t len) const485 bool file::tryLockFromCurrent(int16_t type, off64_t start, off64_t len) const {
486 return lock(F_SETLK,type,SEEK_CUR,start,len);
487 }
488
lockFromCurrent(int16_t type,off64_t len) const489 bool file::lockFromCurrent(int16_t type, off64_t len) const {
490 return lockFromCurrent(type,0,len);
491 }
492
lockFromCurrent(int16_t type,off64_t start,off64_t len) const493 bool file::lockFromCurrent(int16_t type, off64_t start, off64_t len) const {
494 return lock(F_SETLKW,type,SEEK_CUR,start,len);
495 }
496
checkLockFromCurrent(int16_t type,off64_t len,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const497 bool file::checkLockFromCurrent(int16_t type, off64_t len,
498 int16_t *conftype, int16_t *confwhence,
499 off64_t *confstart, off64_t *conflen) const {
500 return checkLockFromCurrent(type,0,len,
501 conftype,confwhence,confstart,conflen);
502 }
503
checkLockFromCurrent(int16_t type,off64_t start,off64_t len,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const504 bool file::checkLockFromCurrent(int16_t type, off64_t start, off64_t len,
505 int16_t *conftype, int16_t *confwhence,
506 off64_t *confstart, off64_t *conflen) const {
507 return checkLock(type,SEEK_CUR,start,len,
508 conftype,confwhence,confstart,conflen);
509 }
510
unlockFromCurrent(off64_t len) const511 bool file::unlockFromCurrent(off64_t len) const {
512 return unlockFromCurrent(0,len);
513 }
514
unlockFromCurrent(off64_t start,off64_t len) const515 bool file::unlockFromCurrent(off64_t start, off64_t len) const {
516 return unlock(SEEK_CUR,start,len);
517 }
518
tryLockFromEnd(int16_t type,off64_t len) const519 bool file::tryLockFromEnd(int16_t type, off64_t len) const {
520 return tryLockFromEnd(type,0,len);
521 }
522
tryLockFromEnd(int16_t type,off64_t start,off64_t len) const523 bool file::tryLockFromEnd(int16_t type, off64_t start, off64_t len) const {
524 return lock(F_SETLK,type,SEEK_END,start,len);
525 }
526
lockFromEnd(int16_t type,off64_t len) const527 bool file::lockFromEnd(int16_t type, off64_t len) const {
528 return lockFromEnd(type,0,len);
529 }
530
lockFromEnd(int16_t type,off64_t start,off64_t len) const531 bool file::lockFromEnd(int16_t type, off64_t start, off64_t len) const {
532 return lock(F_SETLKW,type,SEEK_END,start,len);
533 }
534
checkLockFromEnd(int16_t type,off64_t len,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const535 bool file::checkLockFromEnd(int16_t type, off64_t len,
536 int16_t *conftype, int16_t *confwhence,
537 off64_t *confstart, off64_t *conflen) const {
538 return checkLockFromEnd(type,0,len,
539 conftype,confwhence,confstart,conflen);
540 }
541
checkLockFromEnd(int16_t type,off64_t start,off64_t len,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const542 bool file::checkLockFromEnd(int16_t type, off64_t start, off64_t len,
543 int16_t *conftype, int16_t *confwhence,
544 off64_t *confstart, off64_t *conflen) const {
545 return checkLock(type,SEEK_END,start,len,
546 conftype,confwhence,confstart,conflen);
547 }
548
unlockFromEnd(off64_t len) const549 bool file::unlockFromEnd(off64_t len) const {
550 return unlockFromEnd(0,len);
551 }
552
unlockFromEnd(off64_t start,off64_t len) const553 bool file::unlockFromEnd(off64_t start, off64_t len) const {
554 return unlock(SEEK_END,start,len);
555 }
556
tryLockRemainder(int16_t type,off64_t start) const557 bool file::tryLockRemainder(int16_t type, off64_t start) const {
558 return lock(F_SETLK,type,SEEK_SET,start,0);
559 }
560
lockRemainder(int16_t type,off64_t start) const561 bool file::lockRemainder(int16_t type, off64_t start) const {
562 return lock(F_SETLKW,type,SEEK_SET,start,0);
563 }
564
checkLockRemainder(int16_t type,off64_t start,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const565 bool file::checkLockRemainder(int16_t type, off64_t start,
566 int16_t *conftype, int16_t *confwhence,
567 off64_t *confstart, off64_t *conflen) const {
568 return checkLock(type,SEEK_SET,start,0,
569 conftype,confwhence,confstart,conflen);
570 }
571
unlockRemainder(off64_t start) const572 bool file::unlockRemainder(off64_t start) const {
573 return unlock(SEEK_SET,start,0);
574 }
575
tryLockRemainderFromCurrent(int16_t type) const576 bool file::tryLockRemainderFromCurrent(int16_t type) const {
577 return tryLockRemainderFromCurrent(type,0);
578 }
579
tryLockRemainderFromCurrent(int16_t type,off64_t start) const580 bool file::tryLockRemainderFromCurrent(int16_t type, off64_t start) const {
581 return lock(F_SETLK,type,SEEK_CUR,start,0);
582 }
583
lockRemainderFromCurrent(int16_t type) const584 bool file::lockRemainderFromCurrent(int16_t type) const {
585 return lockRemainderFromCurrent(type,0);
586 }
587
lockRemainderFromCurrent(int16_t type,off64_t start) const588 bool file::lockRemainderFromCurrent(int16_t type, off64_t start) const {
589 return lock(F_SETLKW,type,SEEK_CUR,start,0);
590 }
591
checkLockRemainderFromCurrent(int16_t type,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const592 bool file::checkLockRemainderFromCurrent(int16_t type,
593 int16_t *conftype, int16_t *confwhence,
594 off64_t *confstart, off64_t *conflen) const {
595 return checkLockRemainderFromCurrent(type,0,
596 conftype,confwhence,confstart,conflen);
597 }
598
checkLockRemainderFromCurrent(int16_t type,off64_t start,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const599 bool file::checkLockRemainderFromCurrent(int16_t type, off64_t start,
600 int16_t *conftype, int16_t *confwhence,
601 off64_t *confstart, off64_t *conflen) const {
602 return checkLock(type,SEEK_CUR,start,0,
603 conftype,confwhence,confstart,conflen);
604 }
605
unlockRemainderFromCurrent() const606 bool file::unlockRemainderFromCurrent() const {
607 return unlockRemainderFromCurrent(0);
608 }
609
unlockRemainderFromCurrent(off64_t start) const610 bool file::unlockRemainderFromCurrent(off64_t start) const {
611 return unlock(SEEK_CUR,start,0);
612 }
613
tryLockRemainderFromEnd(int16_t type) const614 bool file::tryLockRemainderFromEnd(int16_t type) const {
615 return tryLockRemainderFromEnd(type,0);
616 }
617
tryLockRemainderFromEnd(int16_t type,off64_t start) const618 bool file::tryLockRemainderFromEnd(int16_t type, off64_t start) const {
619 return lock(F_SETLK,type,SEEK_END,start,0);
620 }
621
lockRemainderFromEnd(int16_t type) const622 bool file::lockRemainderFromEnd(int16_t type) const {
623 return lockRemainderFromEnd(type,0);
624 }
625
lockRemainderFromEnd(int16_t type,off64_t start) const626 bool file::lockRemainderFromEnd(int16_t type, off64_t start) const {
627 return lock(F_SETLKW,type,SEEK_END,start,0);
628 }
629
checkLockRemainderFromEnd(int16_t type,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const630 bool file::checkLockRemainderFromEnd(int16_t type,
631 int16_t *conftype, int16_t *confwhence,
632 off64_t *confstart, off64_t *conflen) const {
633 return checkLockRemainderFromEnd(type,0,
634 conftype,confwhence,confstart,conflen);
635 }
636
checkLockRemainderFromEnd(int16_t type,off64_t start,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const637 bool file::checkLockRemainderFromEnd(int16_t type, off64_t start,
638 int16_t *conftype, int16_t *confwhence,
639 off64_t *confstart, off64_t *conflen) const {
640 return checkLock(type,SEEK_END,start,0,
641 conftype,confwhence,confstart,conflen);
642 }
643
sequentialAccess(off64_t start,size_t len) const644 bool file::sequentialAccess(off64_t start, size_t len) const {
645 #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \
646 defined(POSIX_FADV_SEQUENTIAL)
647 return posixFadvise(start,len,POSIX_FADV_SEQUENTIAL);
648 #else
649 return true;
650 #endif
651 }
652
randomAccess(off64_t start,size_t len) const653 bool file::randomAccess(off64_t start, size_t len) const {
654 #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \
655 defined(POSIX_FADV_RANDOM)
656 return posixFadvise(start,len,POSIX_FADV_RANDOM);
657 #else
658 return true;
659 #endif
660 }
661
onlyOnce(off64_t start,size_t len) const662 bool file::onlyOnce(off64_t start, size_t len) const {
663 #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \
664 defined(POSIX_FADV_NOREUSE)
665 return posixFadvise(start,len,POSIX_FADV_NOREUSE);
666 #else
667 return true;
668 #endif
669 }
670
willNeed(off64_t start,size_t len) const671 bool file::willNeed(off64_t start, size_t len) const {
672 #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \
673 defined(POSIX_FADV_WILLNEED)
674 return posixFadvise(start,len,POSIX_FADV_WILLNEED);
675 #else
676 return true;
677 #endif
678 }
679
wontNeed(off64_t start,size_t len) const680 bool file::wontNeed(off64_t start, size_t len) const {
681 #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \
682 defined(POSIX_FADV_DONTNEED)
683 return posixFadvise(start,len,POSIX_FADV_DONTNEED);
684 #else
685 return true;
686 #endif
687 }
688
normalAccess(off64_t start,size_t len) const689 bool file::normalAccess(off64_t start, size_t len) const {
690 #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \
691 defined(POSIX_FADV_NORMAL)
692 return posixFadvise(start,len,POSIX_FADV_NORMAL);
693 #else
694 return true;
695 #endif
696 }
697
reserve(off64_t start,size_t len) const698 bool file::reserve(off64_t start, size_t len) const {
699 #ifdef RUDIMENTS_HAVE_POSIX_FALLOCATE
700 int32_t result;
701 error::clearError();
702 do {
703 result=posix_fallocate(fd(),start,len);
704 } while (result==-1 && error::getErrorNumber()==EINTR);
705 return !result;
706 #else
707 return false;
708 #endif
709 }
710
truncate(const char * filename)711 bool file::truncate(const char *filename) {
712 return truncate(filename,0);
713 }
714
truncate(const char * filename,off64_t length)715 bool file::truncate(const char *filename, off64_t length) {
716 #ifdef RUDIMENTS_HAVE_TRUNCATE
717 int32_t result;
718 do {
719 result=::truncate(filename,length);
720 } while (result==-1 && error::getErrorNumber()==-1);
721 return !result;
722 #else
723 file f;
724 return f.open(filename,O_WRONLY) && f.truncate(length);
725 #endif
726 }
727
truncate() const728 bool file::truncate() const {
729 return truncate((off64_t)0);
730 }
731
truncate(off64_t length) const732 bool file::truncate(off64_t length) const {
733 int32_t result;
734 do {
735 #if defined(RUDIMENTS_HAVE_FTRUNCATE) || \
736 defined(RUDIMENTS_HAVE_UNDEFINED_FTRUNCATE)
737 result=::ftruncate(fd(),length);
738 #elif defined(RUDIMENTS_HAVE__CHSIZE_S)
739 result=_chsize_s(fd(),length);
740 #elif defined(RUDIMENTS_HAVE_SETENDOFFILE)
741 return (setPositionRelativeToBeginning(0)!=-1 &&
742 SetEndOfFile((HANDLE)
743 getHandleFromFileDescriptor(fd()))==
744 TRUE);
745 #else
746 #error no ftruncate or anything like it
747 #endif
748 } while (result==-1 && error::getErrorNumber()==-1);
749 return !result;
750 }
751
unlockRemainderFromEnd() const752 bool file::unlockRemainderFromEnd() const {
753 return unlockRemainderFromEnd(0);
754 }
755
unlockRemainderFromEnd(off64_t start) const756 bool file::unlockRemainderFromEnd(off64_t start) const {
757 return unlock(SEEK_END,start,0);
758 }
759
setPositionRelativeToBeginning(off64_t offset) const760 off64_t file::setPositionRelativeToBeginning(off64_t offset) const {
761 return lseek(offset,SEEK_SET);
762 }
763
setPositionRelativeToCurrent(off64_t offset) const764 off64_t file::setPositionRelativeToCurrent(off64_t offset) const {
765 return lseek(offset,SEEK_CUR);
766 }
767
setPositionRelativeToEnd(off64_t offset) const768 off64_t file::setPositionRelativeToEnd(off64_t offset) const {
769 return lseek(offset,SEEK_END);
770 }
771
getCurrentPosition() const772 off64_t file::getCurrentPosition() const {
773 return lseek(0,SEEK_CUR);
774 }
775
lseek(off64_t offset,int32_t whence) const776 off64_t file::lseek(off64_t offset, int32_t whence) const {
777 int32_t result;
778 error::clearError();
779 do {
780 #if defined(RUDIMENTS_HAVE__LSEEK)
781 result=_lseek(fd(),offset,whence);
782 #elif defined(RUDIMENTS_HAVE_LSEEK)
783 result=::lseek(fd(),offset,whence);
784 #else
785 #error no lseek or anything like it
786 #endif
787 } while (result==-1 && error::getErrorNumber()==EINTR);
788 return result;
789 }
790
exists(const char * filename)791 bool file::exists(const char *filename) {
792 return accessible(filename,F_OK);
793 }
794
readable(const char * filename)795 bool file::readable(const char *filename) {
796 return accessible(filename,R_OK);
797 }
798
writeable(const char * filename)799 bool file::writeable(const char *filename) {
800 return accessible(filename,W_OK);
801 }
802
executable(const char * filename)803 bool file::executable(const char *filename) {
804 return accessible(filename,X_OK);
805 }
806
accessible(const char * filename,int32_t mode)807 bool file::accessible(const char *filename, int32_t mode) {
808 int32_t result;
809 error::clearError();
810 do {
811 #if defined(RUDIMENTS_HAVE__ACCESS_S)
812 result=(!charstring::isNullOrEmpty(filename))?
813 _access_s(filename,mode):-1;
814 #elif defined(RUDIMENTS_HAVE_ACCESS)
815 result=access(filename,mode);
816 #else
817 #error no access or anything like it
818 #endif
819 } while (result==-1 && error::getErrorNumber()==EINTR);
820 return !result;
821 }
822
getCurrentProperties()823 bool file::getCurrentProperties() {
824 int32_t result;
825 error::clearError();
826 do {
827 result=fstat(fd(),&pvt->_st);
828 } while (result==-1 && error::getErrorNumber()==EINTR);
829 if (result) {
830 return false;
831 }
832 #if defined(RUDIMENTS_HAVE_GETFILETYPE)
833 pvt->_filetype=GetFileType(
834 (HANDLE)getHandleFromFileDescriptor(fd()));
835 #endif
836 #ifndef RUDIMENTS_HAVE_BLKSIZE_T
837 filesystem fs;
838 pvt->_blocksize=0;
839 if (fs.open(pvt->_name)) {
840 pvt->_blocksize=fs.getBlockSize();
841 }
842 #endif
843 #if defined(RUDIMENTS_HAVE_GETFILEINFORMATIONBYHANDLE)
844 // On Windows, the st_ino and st_dev members aren't set.
845 // Get the file index and volume serial numbers for these.
846
847 BY_HANDLE_FILE_INFORMATION bhfi;
848 if (GetFileInformationByHandle(
849 (HANDLE)getHandleFromFileDescriptor(fd()),
850 &bhfi)==TRUE) {
851
852 pvt->_inode=(((uint64_t)bhfi.nFileIndexHigh)<<32)|
853 bhfi.nFileIndexLow;
854 pvt->_st.st_dev=bhfi.dwVolumeSerialNumber;
855 }
856 #endif
857 #if defined(RUDIMENTS_HAVE_GETSECURITYINFO)
858
859 // On Windows, the st_mode isn't set correctly. Get the DACL
860 // of the file and convert it to a mode_t...
861
862 // get the security information
863 PACL dacl=NULL;
864 PSECURITY_DESCRIPTOR ppsd=NULL;
865 if (GetSecurityInfo((HANDLE)getHandleFromFileDescriptor(fd()),
866 SE_FILE_OBJECT,
867 DACL_SECURITY_INFORMATION,
868 NULL,NULL,&dacl,NULL,&ppsd)!=
869 ERROR_SUCCESS) {
870 return false;
871 }
872
873 // convert the dacl to perms
874 pvt->_st.st_mode=permissions::daclToPermOctal((void *)dacl);
875
876 // clean up
877 LocalFree(ppsd);
878 #endif
879 return true;
880 }
881
stat(const char * filename,void * st)882 bool file::stat(const char *filename, void *st) {
883 int32_t result;
884 error::clearError();
885 do {
886 result=::stat(filename,(struct stat *)st);
887 } while (result==-1 && error::getErrorNumber()==EINTR);
888 return (result!=-1);
889 }
890
getPermissions() const891 mode_t file::getPermissions() const {
892 return pvt->_st.st_mode;
893 }
894
getOwnerUserId() const895 uid_t file::getOwnerUserId() const {
896 return pvt->_st.st_uid;
897 }
898
getOwnerGroupId() const899 gid_t file::getOwnerGroupId() const {
900 return pvt->_st.st_gid;
901 }
902
getSize() const903 off64_t file::getSize() const {
904 return pvt->_st.st_size;
905 }
906
getBlockSize() const907 blksize_t file::getBlockSize() const {
908 #ifdef RUDIMENTS_HAVE_BLKSIZE_T
909 return pvt->_st.st_blksize;
910 #else
911 return pvt->_blocksize;
912 #endif
913 }
914
getBlockCount() const915 blkcnt_t file::getBlockCount() const {
916 #ifdef RUDIMENTS_HAVE_BLKCNT_T
917 return pvt->_st.st_blocks;
918 #else
919 off64_t size=getSize();
920 blksize_t blksize=getBlockSize();
921 return (size && blksize)?(size/blksize+1):0;
922 #endif
923 }
924
925 #ifndef RUDIMENTS_HAVE_S_ISSOCK
926 #define S_ISSOCK(m) (((m&0140000)==0140000)?1:0)
927 #endif
928
isSocket() const929 int32_t file::isSocket() const {
930 #if defined(_S_IFSOCK)
931 return ((pvt->_st.st_mode&_S_IFSOCK)==_S_IFSOCK);
932 #elif defined(S_IFSOCK)
933 return ((pvt->_st.st_mode&S_IFSOCK)==S_IFSOCK);
934 #else
935 return S_ISSOCK(pvt->_st.st_mode);
936 #endif
937 }
938
939 #ifndef RUDIMENTS_HAVE_S_ISLNK
940 #define S_ISLNK(m) (((m&0120000)==0120000)?1:0)
941 #endif
942
isSymbolicLink() const943 int32_t file::isSymbolicLink() const {
944 #if defined(_S_IFLNK)
945 return ((pvt->_st.st_mode&_S_IFLNK)==_S_IFLNK);
946 #elif defined(S_IFLNK)
947 return ((pvt->_st.st_mode&S_IFLNK)==S_IFLNK);
948 #else
949 return S_ISLNK(pvt->_st.st_mode);
950 #endif
951 }
952
isRegularFile() const953 int32_t file::isRegularFile() const {
954 #if defined(RUDIMENTS_HAVE_GETFILETYPE)
955 return (pvt->_filetype==FILE_TYPE_DISK);
956 #elif defined(_S_IFREG)
957 return ((pvt->_st.st_mode&_S_IFREG)==_S_IFREG);
958 #elif defined(S_IFREG)
959 return ((pvt->_st.st_mode&S_IFREG)==S_IFREG);
960 #else
961 return S_ISREG(pvt->_st.st_mode);
962 #endif
963 }
964
965 #ifndef RUDIMENTS_HAVE_S_ISBLK
966 #define S_ISBLK(m) (((m&0060000)==0060000)?1:0)
967 #endif
968
isBlockDevice() const969 int32_t file::isBlockDevice() const {
970 #if defined(_S_IFBLK)
971 return ((pvt->_st.st_mode&_S_IFBLK)==_S_IFBLK);
972 #elif defined(S_IFBLK)
973 return ((pvt->_st.st_mode&S_IFBLK)==S_IFBLK);
974 #else
975 return S_ISBLK(pvt->_st.st_mode);
976 #endif
977 }
978
isDirectory() const979 int32_t file::isDirectory() const {
980 #if defined(_S_IFDIR)
981 return ((pvt->_st.st_mode&_S_IFDIR)==_S_IFDIR);
982 #elif defined(S_IFDIR)
983 return ((pvt->_st.st_mode&S_IFDIR)==S_IFDIR);
984 #else
985 return S_ISDIR(pvt->_st.st_mode);
986 #endif
987 }
988
isCharacterDevice() const989 int32_t file::isCharacterDevice() const {
990 #if defined(RUDIMENTS_HAVE_GETFILETYPE)
991 return (pvt->_filetype==FILE_TYPE_CHAR);
992 #elif defined(_S_IFCHR)
993 return ((pvt->_st.st_mode&_S_IFCHR)==_S_IFCHR);
994 #elif defined(S_IFCHR)
995 return ((pvt->_st.st_mode&S_IFCHR)==S_IFCHR);
996 #else
997 return S_ISCHR(pvt->_st.st_mode);
998 #endif
999 }
1000
isFifo() const1001 int32_t file::isFifo() const {
1002 #if defined(RUDIMENTS_HAVE_GETFILETYPE)
1003 return (pvt->_filetype==FILE_TYPE_PIPE);
1004 #elif defined(_S_IFIFO)
1005 return ((pvt->_st.st_mode&_S_IFIFO)==_S_IFIFO);
1006 #elif defined(S_IFIFO)
1007 return ((pvt->_st.st_mode&S_IFIFO)==S_IFIFO);
1008 #else
1009 return S_ISFIFO(pvt->_st.st_mode);
1010 #endif
1011 }
1012
getLastAccessTime() const1013 time_t file::getLastAccessTime() const {
1014 return pvt->_st.st_atime;
1015 }
1016
getLastModificationTime() const1017 time_t file::getLastModificationTime() const {
1018 return pvt->_st.st_mtime;
1019 }
1020
getLastChangeTime() const1021 time_t file::getLastChangeTime() const {
1022 return pvt->_st.st_ctime;
1023 }
1024
1025
getDevice() const1026 dev_t file::getDevice() const {
1027 return pvt->_st.st_dev;
1028 }
1029
getDeviceType() const1030 dev_t file::getDeviceType() const {
1031 return pvt->_st.st_rdev;
1032 }
1033
getInode() const1034 uint64_t file::getInode() const {
1035 #if defined(RUDIMENTS_HAVE_GETFILEINFORMATIONBYHANDLE)
1036 return pvt->_inode;
1037 #else
1038 // some platforms (OpenVMS) require this cast
1039 return (uint64_t)pvt->_st.st_ino;
1040 #endif
1041 }
1042
getNumberOfHardLinks() const1043 nlink_t file::getNumberOfHardLinks() const {
1044 return pvt->_st.st_nlink;
1045 }
1046
getCurrentPropertiesOnOpen()1047 void file::getCurrentPropertiesOnOpen() {
1048 pvt->_getcurrentpropertiesonopen=true;
1049 }
1050
dontGetCurrentPropertiesOnOpen()1051 void file::dontGetCurrentPropertiesOnOpen() {
1052 pvt->_getcurrentpropertiesonopen=false;
1053 }
1054
lock(int32_t method,int16_t type,int16_t whence,off64_t start,off64_t len) const1055 bool file::lock(int32_t method, int16_t type,
1056 int16_t whence, off64_t start, off64_t len) const {
1057 #if defined(RUDIMENTS_HAVE_FCNTL)
1058 struct flock lck;
1059 lck.l_type=type;
1060 lck.l_whence=whence;
1061 lck.l_start=start;
1062 lck.l_len=len;
1063 return !fCntl(method,reinterpret_cast<long>(&lck));
1064 #elif defined(RUDIMENTS_HAVE_LOCKFILEEX)
1065 off64_t cur=getCurrentPosition();
1066 if (cur==-1) {
1067 return false;
1068 }
1069 LARGE_INTEGER lockstart;
1070 lockstart.QuadPart=lseek(start,whence);
1071 if (lockstart.QuadPart==-1) {
1072 return false;
1073 }
1074 if (setPositionRelativeToBeginning(cur)==-1) {
1075 return false;
1076 }
1077 OVERLAPPED ol;
1078 bytestring::zero((void *)&ol,sizeof(ol));
1079 ol.Offset=lockstart.LowPart;
1080 ol.OffsetHigh=lockstart.HighPart;
1081 LARGE_INTEGER locklength;
1082 locklength.QuadPart=(len)?len:MAXDWORD;
1083 DWORD flags=
1084 ((type&F_WRLCK)?LOCKFILE_EXCLUSIVE_LOCK:0)|
1085 ((method==F_SETLK)?LOCKFILE_FAIL_IMMEDIATELY:0);
1086 return LockFileEx((HANDLE)getHandleFromFileDescriptor(fd()),
1087 flags,
1088 0,
1089 locklength.LowPart,
1090 locklength.HighPart,
1091 &ol)!=FALSE;
1092 #else
1093 #error no fcntl, LockFile or anything like it
1094 #endif
1095 }
1096
checkLock(int16_t type,int16_t whence,off64_t start,off64_t len,int16_t * conftype,int16_t * confwhence,off64_t * confstart,off64_t * conflen) const1097 bool file::checkLock(int16_t type, int16_t whence,
1098 off64_t start, off64_t len,
1099 int16_t *conftype, int16_t *confwhence,
1100 off64_t *confstart, off64_t *conflen) const {
1101 #if defined(RUDIMENTS_HAVE_FCNTL)
1102 struct flock lck;
1103 lck.l_type=type;
1104 lck.l_whence=whence;
1105 lck.l_start=start;
1106 lck.l_len=len;
1107 int32_t result=fCntl(F_GETLK,reinterpret_cast<long>(&lck));
1108 *conftype=lck.l_type;
1109 *confwhence=lck.l_whence;
1110 *confstart=lck.l_start;
1111 *conflen=lck.l_len;
1112 return !result;
1113 #elif defined(RUDIMENTS_HAVE_LOCKFILEEX)
1114 // Windows doesn't appear to support this at all.
1115 // I guess we'll return false, meaning not locked.
1116 return false;
1117 #else
1118 #error no fcntl(F_GETLK), LockFile or anything like it
1119 #endif
1120 }
1121
unlock(int16_t whence,off64_t start,off64_t len) const1122 bool file::unlock(int16_t whence, off64_t start, off64_t len) const {
1123 #if defined(RUDIMENTS_HAVE_FCNTL)
1124 struct flock lck;
1125 lck.l_type=F_UNLCK;
1126 lck.l_whence=whence;
1127 lck.l_start=start;
1128 lck.l_len=len;
1129 return !fCntl(F_SETLK,reinterpret_cast<long>(&lck));
1130 #elif defined(RUDIMENTS_HAVE_LOCKFILEEX)
1131 off64_t cur=getCurrentPosition();
1132 if (cur==-1) {
1133 return false;
1134 }
1135 LARGE_INTEGER lockstart;
1136 lockstart.QuadPart=lseek(start,whence);
1137 if (lockstart.QuadPart==-1) {
1138 return false;
1139 }
1140 if (setPositionRelativeToBeginning(cur)==-1) {
1141 return false;
1142 }
1143 LARGE_INTEGER locklength;
1144 locklength.QuadPart=(len)?len:MAXDWORD;
1145 return UnlockFile((HANDLE)getHandleFromFileDescriptor(fd()),
1146 lockstart.LowPart,
1147 lockstart.HighPart,
1148 locklength.LowPart,
1149 locklength.HighPart)!=FALSE;
1150 #else
1151 #error no fcntl, UnlockFile or anything like it
1152 #endif
1153 }
1154
setPermissions(mode_t perms) const1155 bool file::setPermissions(mode_t perms) const {
1156 return permissions::setFilePermissions(fd(),perms);
1157 }
1158
changeOwner(const char * newuser,const char * newgroup) const1159 bool file::changeOwner(const char *newuser, const char *newgroup) const {
1160 return changeOwner(userentry::getUserId(newuser),
1161 groupentry::getGroupId(newgroup));
1162 }
1163
changeOwner(uid_t uid,gid_t gid) const1164 bool file::changeOwner(uid_t uid, gid_t gid) const {
1165 #if defined(RUDIMENTS_HAVE_FCHOWN)
1166
1167 int32_t result;
1168 error::clearError();
1169 do {
1170 result=fchown(fd(),uid,gid);
1171 } while (result==-1 && error::getErrorNumber()==EINTR);
1172 return !result;
1173
1174 #elif defined(RUDIMENTS_HAVE_SETSECURITYINFO)
1175
1176 // get the file handle
1177 HANDLE fh=(HANDLE)getHandleFromFileDescriptor(fd());
1178 if (fh==INVALID_HANDLE_VALUE) {
1179 return false;
1180 }
1181
1182 // get the user and group sid's
1183 userentry ue;
1184 groupentry ge;
1185 if (!ue.initialize(uid) || !ge.initialize(gid)) {
1186 return false;
1187 }
1188
1189 // adjust my privileges so I can set the owner
1190 HANDLE th=NULL;
1191 if (!OpenProcessToken(GetCurrentProcess(),
1192 TOKEN_ADJUST_PRIVILEGES,&th)) {
1193 return false;
1194 }
1195 TOKEN_PRIVILEGES priv;
1196 priv.PrivilegeCount=1;
1197 priv.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
1198 const char *privs[5]={
1199 SE_BACKUP_NAME,
1200 SE_RESTORE_NAME,
1201 SE_SECURITY_NAME,
1202 SE_TAKE_OWNERSHIP_NAME,
1203 NULL
1204 };
1205 for (const char * const *p=privs; *p; p++) {
1206 LUID luid;
1207 if (!LookupPrivilegeValue(NULL,*p,&luid)) {
1208 CloseHandle(th);
1209 return false;
1210 }
1211 priv.Privileges[0].Luid=luid;
1212 if (!AdjustTokenPrivileges(th,FALSE,&priv,
1213 sizeof(TOKEN_PRIVILEGES),NULL,NULL)) {
1214 CloseHandle(th);
1215 return false;
1216 }
1217 }
1218
1219 // set the owner/group
1220 if (SetSecurityInfo(fh,
1221 SE_FILE_OBJECT,
1222 OWNER_SECURITY_INFORMATION|
1223 GROUP_SECURITY_INFORMATION,
1224 (PSID)ue.getSid(),
1225 (PSID)ge.getSid(),
1226 NULL,NULL)!=ERROR_SUCCESS) {
1227 CloseHandle(th);
1228 return false;
1229 }
1230
1231 // Below is the original way I implemented this.
1232 // BuildSecurityDescriptor crashes on Windows 8 though.
1233 // There are other issues too. Files are kernel objects, so I
1234 // should probably use Get/SetKernelObjectSecurity instead of
1235 // Get/SetUserObjectSecurity. Though the docs also say to use
1236 // SetSecurityInfo instead of SetKernelObjectSecurity for
1237 // filesystem objects, which is what I changed it to.
1238 #if 0
1239 // FIXME: do these need to be freed?
1240 PSID usid=(PSID)bytestring::duplicate(ue.getSid(),
1241 ue.getSidSize());
1242 PSID gsid=(PSID)bytestring::duplicate(ge.getSid(),
1243 ge.getSidSize());
1244
1245 // build trustees
1246 TRUSTEE ut;
1247 bytestring::zero(&ut,sizeof(ut));
1248 BuildTrusteeWithSid(&ut,usid);
1249 TRUSTEE gt;
1250 bytestring::zero(>,sizeof(gt));
1251 BuildTrusteeWithSid(>,gsid);
1252
1253 // get the existing owner/group security info for the file
1254 // into a security descriptor
1255 DWORD sdsize=0;
1256 SECURITY_INFORMATION sinfo=
1257 OWNER_SECURITY_INFORMATION|
1258 GROUP_SECURITY_INFORMATION;
1259 GetUserObjectSecurity(fh,&sinfo,NULL,0,&sdsize);
1260 PSECURITY_DESCRIPTOR sdesc=
1261 (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,sdsize);
1262 if (!sdesc) {
1263 CloseHandle(th);
1264 return false;
1265 }
1266 bytestring::zero(sdesc,sdsize);
1267 if (!GetUserObjectSecurity(fh,&sinfo,sdesc,sdsize,&sdsize)) {
1268 LocalFree(sdesc);
1269 CloseHandle(th);
1270 return false;
1271 }
1272
1273 // build a new security descriptor, starting with the existing
1274 // security descriptor, but updating the user/group info
1275 PSECURITY_DESCRIPTOR newsdesc=NULL;
1276 DWORD result=BuildSecurityDescriptor(
1277 &ut,>,
1278 0,NULL,0,NULL,
1279 sdesc,&sdsize,&newsdesc);
1280 if (result!=ERROR_SUCCESS) {
1281 LocalFree(sdesc);
1282 LocalFree(newsdesc);
1283 CloseHandle(th);
1284 return false;
1285 }
1286
1287 // apply the new security descriptor to the file
1288 if (!SetUserObjectSecurity(fh,&sinfo,newsdesc)) {
1289 LocalFree(sdesc);
1290 LocalFree(newsdesc);
1291 CloseHandle(th);
1292 return false;
1293 }
1294
1295 // clean up
1296 LocalFree(sdesc);
1297 LocalFree(newsdesc);
1298 #endif
1299 CloseHandle(th);
1300 return true;
1301 #else
1302 RUDIMENTS_SET_ENOSYS
1303 return false;
1304 #endif
1305 }
1306
setPermissions(const char * filename,mode_t perms)1307 bool file::setPermissions(const char *filename, mode_t perms) {
1308 return permissions::setFilePermissions(filename,perms);
1309 }
1310
changeOwner(const char * filename,const char * newuser,const char * newgroup)1311 bool file::changeOwner(const char *filename, const char *newuser,
1312 const char *newgroup) {
1313 file fl;
1314 return (fl.open(filename,O_RDWR) && fl.changeOwner(newuser,newgroup));
1315 }
1316
changeOwner(const char * filename,uid_t uid,gid_t gid)1317 bool file::changeOwner(const char *filename, uid_t uid, gid_t gid) {
1318 file fl;
1319 return (fl.open(filename,O_RDWR) && fl.changeOwner(uid,gid));
1320 }
1321
canChangeOwner(const char * filename)1322 bool file::canChangeOwner(const char *filename) {
1323 return !pathConf(filename,_PC_CHOWN_RESTRICTED);
1324 }
1325
canChangeOwner() const1326 bool file::canChangeOwner() const {
1327 return !fpathConf(_PC_CHOWN_RESTRICTED);
1328 }
1329
rename(const char * oldpath,const char * newpath)1330 bool file::rename(const char *oldpath, const char *newpath) {
1331 int32_t result;
1332 error::clearError();
1333 do {
1334 result=::rename(oldpath,newpath);
1335 } while (result==-1 && error::getErrorNumber()==EINTR);
1336 return !result;
1337 }
1338
remove(const char * filename)1339 bool file::remove(const char *filename) {
1340 int32_t result;
1341 error::clearError();
1342 do {
1343 #if defined(RUDIMENTS_HAVE__UNLINK)
1344 result=_unlink(filename);
1345 #elif defined(RUDIMENTS_HAVE_UNLINK)
1346 result=unlink(filename);
1347 #else
1348 #error no unlink or anything like it
1349 #endif
1350 } while (result==-1 && error::getErrorNumber()==EINTR);
1351 return !result;
1352 }
1353
createHardLink(const char * oldpath,const char * newpath)1354 bool file::createHardLink(const char *oldpath, const char *newpath) {
1355 #if defined(RUDIMENTS_HAVE_LINK)
1356 int32_t result;
1357 error::clearError();
1358 do {
1359 result=link(oldpath,newpath);
1360 } while (result==-1 && error::getErrorNumber()==EINTR);
1361 return !result;
1362 #elif defined(RUDIMENTS_HAVE_LOADLIBRARY)
1363 bool retval=false;
1364 HMODULE lib=LoadLibrary("KERNEL32");
1365 if (lib) {
1366 bool (*proc)(LPCSTR,LPCSTR,
1367 LPSECURITY_ATTRIBUTES)=
1368 (bool (*)(LPCSTR,LPCSTR,
1369 LPSECURITY_ATTRIBUTES))
1370 GetProcAddress(lib,"CreateHardLinkA");
1371 if (proc) {
1372 retval=proc(newpath,oldpath,NULL);
1373 }
1374 FreeLibrary(lib);
1375 }
1376 return retval;
1377 #else
1378 RUDIMENTS_SET_ENOSYS
1379 return false;
1380 #endif
1381 }
1382
createSymbolicLink(const char * oldpath,const char * newpath)1383 bool file::createSymbolicLink(const char *oldpath, const char *newpath) {
1384 #if defined(RUDIMENTS_HAVE_SYMLINK)
1385 int32_t result;
1386 error::clearError();
1387 do {
1388 result=symlink(oldpath,newpath);
1389 } while (result==-1 && error::getErrorNumber()==EINTR);
1390 return !result;
1391 #else
1392 RUDIMENTS_SET_ENOSYS
1393 return false;
1394 #endif
1395 }
1396
resolveSymbolicLink(const char * filename)1397 char *file::resolveSymbolicLink(const char *filename) {
1398
1399 #if defined(RUDIMENTS_HAVE_READLINK)
1400 size_t inc=directory::maxPathLength(filename);
1401 size_t max=inc*10;
1402 for (size_t size=inc; size<max; size=size+inc) {
1403
1404 // create a buffer to store the path
1405 char *buffer=new char[size];
1406
1407 // read the path into the buffer
1408 int32_t len;
1409 error::clearError();
1410 do {
1411 len=::readlink(filename,buffer,size);
1412 } while (len==-1 && error::getErrorNumber()==EINTR);
1413
1414 if (len==-1) {
1415
1416 // if the call to readlink failed, delete the
1417 // buffer and return NULL
1418 delete[] buffer;
1419 return NULL;
1420
1421 } else if ((size_t)len==size) {
1422
1423 // if the length of the path was the same as
1424 // the buffer size the we didn't get the entire
1425 // path, loop back, increase the size of the
1426 // buffer and try again
1427 delete[] buffer;
1428
1429 } else {
1430 // NULL-terminate the buffer,
1431 // readlink() doesn't do this for us
1432 buffer[len]='\0';
1433 return buffer;
1434 }
1435 }
1436 return NULL;
1437 #else
1438 RUDIMENTS_SET_ENOSYS
1439 return NULL;
1440 #endif
1441 }
1442
sync() const1443 bool file::sync() const {
1444 #if defined(RUDIMENTS_HAVE_FSYNC) || \
1445 defined(RUDIMENTS_HAVE_UNDEFINED_FSYNC)
1446 int32_t result;
1447 error::clearError();
1448 do {
1449 result=fsync(fd());
1450 } while (result==-1 && error::getErrorNumber()==EINTR);
1451 return !result;
1452 #elif defined(RUDIMENTS_HAVE_FLUSHFILEBUFFERS)
1453 return (FlushFileBuffers(
1454 (HANDLE)getHandleFromFileDescriptor(fd()))!=0);
1455 #elif defined(RUDIMENTS_HAVE_COMMIT)
1456 return _commit(fd())==0;
1457 #else
1458 #error no fsync or anything like it
1459 #endif
1460 }
1461
dataSync() const1462 bool file::dataSync() const {
1463 #ifdef RUDIMENTS_HAVE_FDATASYNC
1464 int32_t result;
1465 error::clearError();
1466 do {
1467 result=fdatasync(fd());
1468 } while (result==-1 && error::getErrorNumber()==EINTR);
1469 return !result;
1470 #else
1471 return sync();
1472 #endif
1473 }
1474
setLastAccessTime(const char * filename,time_t lastaccesstime)1475 bool file::setLastAccessTime(const char *filename,
1476 time_t lastaccesstime) {
1477 struct stat st;
1478 if (!stat(filename,&st)) {
1479 return false;
1480 }
1481 return setLastAccessAndModificationTimes(filename,
1482 lastaccesstime,
1483 st.st_mtime);
1484 }
1485
setLastModificationTime(const char * filename,time_t lastmodtime)1486 bool file::setLastModificationTime(const char *filename,
1487 time_t lastmodtime) {
1488 struct stat st;
1489 if (!stat(filename,&st)) {
1490 return false;
1491 }
1492 return setLastAccessAndModificationTimes(filename,
1493 st.st_atime,
1494 lastmodtime);
1495 }
1496
setLastAccessAndModificationTimes(const char * filename,time_t lastaccesstime,time_t lastmodtime)1497 bool file::setLastAccessAndModificationTimes(const char *filename,
1498 time_t lastaccesstime,
1499 time_t lastmodtime) {
1500 #if defined(RUDIMENTS_HAVE_UTIMES_CONST_CHAR) || \
1501 defined(RUDIMENTS_HAVE_UTIMES_CHAR)
1502 timeval tv[2];
1503 tv[0].tv_sec=static_cast<long>(lastaccesstime);
1504 tv[0].tv_usec=0;
1505 tv[1].tv_sec=static_cast<long>(lastmodtime);
1506 tv[1].tv_usec=0;
1507 int32_t result;
1508 error::clearError();
1509 do {
1510 #if defined(RUDIMENTS_HAVE_UTIMES_CONST_CHAR)
1511 result=utimes(filename,tv);
1512 #elif defined(RUDIMENTS_HAVE_UTIMES_CHAR)
1513 result=utimes((char *)filename,tv);
1514 #endif
1515 } while (result==-1 && error::getErrorNumber()==EINTR);
1516 return !result;
1517 #elif defined(RUDIMENTS_HAVE_UTIME)
1518 utimbuf tb;
1519 tb.actime=static_cast<time_t>(lastaccesstime);
1520 tb.modtime=static_cast<time_t>(lastmodtime);
1521 int32_t result;
1522 error::clearError();
1523 do {
1524 result=utime(filename,&tb);
1525 } while (result==-1 && error::getErrorNumber()==EINTR);
1526 return !result;
1527 #elif defined(RUDIMENTS_HAVE_SETFILETIME)
1528
1529 // open the file
1530 HANDLE handle=CreateFile(filename,
1531 FILE_WRITE_ATTRIBUTES,
1532 FILE_SHARE_DELETE|
1533 FILE_SHARE_READ|
1534 FILE_SHARE_WRITE,
1535 NULL,
1536 OPEN_EXISTING,
1537 FILE_ATTRIBUTE_NORMAL|
1538 FILE_FLAG_BACKUP_SEMANTICS,
1539 NULL);
1540 if (handle==INVALID_HANDLE_VALUE) {
1541 return false;
1542 }
1543
1544 // windows time starts at 1/1/1601
1545 // unix time starts at 1/1/1970
1546 // this is the number of seconds between those dates
1547 #define timediff 11644473600
1548
1549 // convert the times from unix to windows format
1550 ULARGE_INTEGER lastaccessfiletime;
1551 lastaccessfiletime.QuadPart=(lastaccesstime+timediff)*10000000;
1552 ULARGE_INTEGER lastmodfiletime;
1553 lastmodfiletime.QuadPart=(lastmodtime+timediff)*10000000;
1554
1555 // set the file times
1556 bool retval=SetFileTime(handle,NULL,
1557 (FILETIME *)&lastaccesstime,
1558 (FILETIME *)&lastmodtime)!=0;
1559
1560 // close the file
1561 CloseHandle(handle);
1562
1563 // return the result
1564 return retval;
1565 #else
1566 RUDIMENTS_SET_ENOSYS
1567 return false;
1568 #endif
1569 }
1570
setLastAccessAndModificationTimes(const char * filename)1571 bool file::setLastAccessAndModificationTimes(const char *filename) {
1572 #if defined(RUDIMENTS_HAVE_UTIMES_CONST_CHAR) || \
1573 defined(RUDIMENTS_HAVE_UTIMES_CHAR)
1574 int32_t result;
1575 error::clearError();
1576 do {
1577 #if defined(RUDIMENTS_HAVE_UTIMES_CONST_CHAR)
1578 result=utimes(filename,NULL);
1579 #elif defined(RUDIMENTS_HAVE_UTIMES_CHAR)
1580 result=utimes((char *)filename,NULL);
1581 #endif
1582 } while (result==-1 && error::getErrorNumber()==EINTR);
1583 return !result;
1584 #else
1585 datetime dt;
1586 dt.getSystemDateAndTime();
1587 return setLastAccessAndModificationTimes(filename,
1588 dt.getEpoch(),
1589 dt.getEpoch());
1590 #endif
1591 }
1592
createFifo(const char * filename,mode_t perms)1593 bool file::createFifo(const char *filename, mode_t perms) {
1594 #if defined(RUDIMENTS_HAVE_MKFIFO)
1595 int32_t result;
1596 error::clearError();
1597 do {
1598 result=mkfifo(filename,perms);
1599 } while (result==-1 && error::getErrorNumber()==EINTR);
1600 return !result;
1601 #elif defined(RUDIMENTS_HAVE_CREATENAMEDPIPE)
1602 HANDLE handle=CreateNamedPipe(filename,0,0,1,
1603 1024,1024,5000,NULL);
1604 if (handle==INVALID_HANDLE_VALUE) {
1605 return false;
1606 }
1607 CloseHandle(handle);
1608 return true;
1609 #else
1610 RUDIMENTS_SET_ENOSYS
1611 return false;
1612 #endif
1613 }
1614
createTemporaryFile(char * templatefilename)1615 int32_t file::createTemporaryFile(char *templatefilename) {
1616 #if defined(RUDIMENTS_HAVE_MKSTEMP)
1617 int32_t result;
1618 error::clearError();
1619 do {
1620 result=mkstemp(templatefilename);
1621 } while (result==-1 && error::getErrorNumber()==EINTR);
1622 return result;
1623 #else
1624 // sanity check on templatefilename
1625 char *lastsix=templatefilename+
1626 charstring::length(templatefilename)-6;
1627 if (charstring::compare(lastsix,"XXXXXX")) {
1628 error::setErrorNumber(EINVAL);
1629 return -1;
1630 }
1631
1632 // replace X's with random characters...
1633
1634 // seed the random number
1635 uint32_t seed=randomnumber::getSeed();
1636
1637 // for each of the 6 characters...
1638 for (uint8_t i=0; i<6; i++) {
1639
1640 // get a random number, scale it to 0-60
1641 seed=randomnumber::generateNumber(seed);
1642 char ch=(char)randomnumber::scaleNumber(seed,0,59);
1643
1644 // translate...
1645 // 0-9 -> '0' - '9'
1646 // 10-34 -> 'A' - 'Z'
1647 // 35-59 -> 'a' - 'z'
1648 if (ch<10) {
1649 ch=ch+'0';
1650 } else if (ch<35) {
1651 ch=ch-10+'A';
1652 } else {
1653 ch=ch-35+'a';
1654 }
1655
1656 // set character
1657 lastsix[i]=ch;
1658 }
1659
1660 // create the file
1661 file f;
1662 if (!f.create(templatefilename,
1663 permissions::evalPermString("rw-r--r--"))) {
1664 return -1;
1665 }
1666
1667 // fake it out so the file won't get
1668 // closed when f is deallocated
1669 int32_t fdesc=f.getFileDescriptor();
1670 f.setFileDescriptor(-1);
1671
1672 // return the file descriptor
1673 return fdesc;
1674 #endif
1675 }
1676
createTemporaryFile(char * templatefilename,mode_t perms)1677 int32_t file::createTemporaryFile(char *templatefilename, mode_t perms) {
1678 int32_t result=createTemporaryFile(templatefilename);
1679 if (result!=1) {
1680 if (!permissions::setFilePermissions(result,perms)) {
1681 remove(templatefilename);
1682 return -1;
1683 }
1684 }
1685 return result;
1686 }
1687
getInternalFileStatisticsStructure()1688 void *file::getInternalFileStatisticsStructure() {
1689 return (void *)&(pvt->_st);
1690 }
1691
dirname(const char * filename)1692 char *file::dirname(const char *filename) {
1693
1694 if (!filename) {
1695 return NULL;
1696 } else if (!charstring::contains(filename,'/') ||
1697 !charstring::compare(filename,".")) {
1698 return charstring::duplicate(".");
1699 } else if (!charstring::compare(filename,"..")) {
1700 return charstring::duplicate("..");
1701 } else if (!charstring::compare(filename,"/")) {
1702 return charstring::duplicate("/");
1703 }
1704
1705 char *retval=charstring::duplicate(filename);
1706 charstring::rightTrim(retval,'/');
1707 char *lastslash=charstring::findLast(retval,'/');
1708 if (lastslash==retval) {
1709 (*(lastslash+1))='\0';
1710 } else {
1711 (*lastslash)='\0';
1712 }
1713 return retval;
1714 }
1715
basename(const char * filename)1716 char *file::basename(const char *filename) {
1717
1718 if (!filename) {
1719 return NULL;
1720 }
1721
1722 char *copy=charstring::duplicate(filename);
1723 charstring::rightTrim(copy,'/');
1724
1725 char *retval;
1726 char *ptr=charstring::findLast(copy,'/');
1727 if (!ptr) {
1728 retval=charstring::duplicate(copy);
1729 } else {
1730 retval=charstring::duplicate(ptr+1);
1731 }
1732 delete[] copy;
1733 return retval;
1734 }
1735
basename(const char * filename,const char * suffix)1736 char *file::basename(const char *filename, const char *suffix) {
1737 char *retval=basename(filename);
1738 char *ptr=charstring::findLast(retval,suffix);
1739 if (!(*(ptr+charstring::length(suffix)))) {
1740 (*ptr)='\0';
1741 }
1742 return retval;
1743 }
1744
eightDotThree(const char * filename)1745 char *file::eightDotThree(const char *filename) {
1746
1747 // FIXME: I'm sure there's an infinitely more efficient way of
1748 // doing this using a static buffer...
1749
1750 // get the base name
1751 char *base=basename(filename);
1752
1753 // get the directory name unless no directory was specified
1754 char *dir=NULL;
1755 if (charstring::compare(base,filename)) {
1756 dir=dirname(filename);
1757 }
1758
1759 // get the suffix and terminate the base at the final dot
1760 char *suffix=NULL;
1761 char *finaldot=charstring::findLast(base,'.');
1762 if (finaldot) {
1763 suffix=charstring::duplicate(finaldot+1);
1764 *finaldot='\0';
1765 }
1766
1767 // Strip illegal characters from the base. If we had to strip any
1768 // characters from the base then we need to force the loop below to
1769 // put a ~# at the end.
1770 bool tryunique=charstring::stripSet(base," .\"/\\[]:;=,");
1771
1772 // strip illegal characters from the suffix
1773 charstring::stripSet(suffix," .\"/\\[]:;=,");
1774
1775 // truncate the base at 8 characters if necessary
1776 if (charstring::length(base)>8) {
1777 *(base+8)='\0';
1778 }
1779
1780 // truncate the suffix at 3 characters if necessary
1781 if (charstring::length(suffix)>3) {
1782 *(suffix+3)='\0';
1783 }
1784
1785 // convert the base and suffix to upper case
1786 charstring::upper(base);
1787 charstring::upper(suffix);
1788
1789 // verify that the filename is unique
1790 uint8_t counter=1;
1791 stringbuffer fullname;
1792 char newbase[9];
1793 charstring::copy(newbase,base);
1794 for (;;) {
1795
1796 // try to come up with a unique name
1797 if (tryunique) {
1798 size_t baselen=charstring::length(base);
1799 if (baselen>6) {
1800 baselen=6;
1801 }
1802 charstring::copy(newbase,base,baselen);
1803 newbase[baselen]='~';
1804 newbase[baselen+1]='0'+counter;
1805 fullname.clear();
1806 counter++;
1807 }
1808
1809 // build the test file name
1810 if (dir) {
1811 fullname.append(dir)->append('/');
1812 }
1813 fullname.append(newbase);
1814 if (suffix) {
1815 fullname.append('.')->append(suffix);
1816 }
1817
1818 // if the name we've come up with is the same as the original
1819 // filename or if a file with the name we've come up with
1820 // doesn't exist, then go ahead and use the name
1821 if (!charstring::compare(fullname.getString(),filename) ||
1822 !exists(fullname.getString())) {
1823 break;
1824 }
1825
1826 // if the counter hits 10 digits then it must not be possible
1827 // to uniquely name this file
1828 if (counter==10) {
1829 delete[] base;
1830 delete[] dir;
1831 delete[] suffix;
1832 return NULL;
1833 }
1834
1835 // try for a unique name the next round
1836 tryunique=true;
1837 }
1838
1839 // get the final name
1840 char *retval=fullname.detachString();
1841
1842 // clean up
1843 delete[] dir;
1844 delete[] base;
1845 delete[] suffix;
1846
1847 // return the name
1848 return retval;
1849 }
1850
generateKey(const char * filename,int32_t id)1851 key_t file::generateKey(const char *filename, int32_t id) {
1852 #if defined(RUDIMENTS_HAVE_FTOK)
1853 #ifdef RUDIMENTS_HAVE_CONST_CHAR_FTOK
1854 return ::ftok(filename,id);
1855 #else
1856 return ::ftok(const_cast<char *>(filename),id);
1857 #endif
1858 #elif !defined( __VMS)
1859 file f;
1860 if (!f.open(filename,O_RDONLY)) {
1861 return -1;
1862 }
1863 return (key_t)((f.getInode() & 0xffff) |
1864 ((f.getDevice() & 0xff) << 16) |
1865 ((id & 0xff) << 24));
1866 #else
1867 RUDIMENTS_SET_ENOSYS
1868 return -1;
1869 #endif
1870 }
1871
maxLinks(const char * filename)1872 int64_t file::maxLinks(const char *filename) {
1873 return pathConf(filename,_PC_LINK_MAX);
1874 }
1875
maxLinks() const1876 int64_t file::maxLinks() const {
1877 return fpathConf(_PC_LINK_MAX);
1878 }
1879
posixFadvise(off64_t offset,off64_t len,int32_t advice) const1880 bool file::posixFadvise(off64_t offset, off64_t len, int32_t advice) const {
1881 #ifdef RUDIMENTS_HAVE_POSIX_FADVISE
1882 int32_t result;
1883 error::clearError();
1884 do {
1885 result=posix_fadvise(fd(),offset,len,advice);
1886 } while (result==-1 && error::getErrorNumber()==EINTR);
1887 return !result;
1888 #else
1889 // on platforms that don't support this, it's ok to just return
1890 // success since really it only gives the filesystem hints
1891 return true;
1892 #endif
1893 }
1894
pathConf(const char * path,int32_t name)1895 int64_t file::pathConf(const char *path, int32_t name) {
1896 #if defined(RUDIMENTS_HAVE_PATHCONF)
1897 int64_t result;
1898 error::clearError();
1899 do {
1900 result=pathconf(path,name);
1901 } while (result==-1 && error::getErrorNumber()==EINTR);
1902 return result;
1903 #else
1904 RUDIMENTS_SET_ENOSYS
1905 return -1;
1906 #endif
1907 }
1908
fpathConf(int32_t name) const1909 int64_t file::fpathConf(int32_t name) const {
1910 #if defined(RUDIMENTS_HAVE_FPATHCONF)
1911 int64_t result;
1912 error::clearError();
1913 do {
1914 result=fpathconf(fd(),name);
1915 } while (result==-1 && error::getErrorNumber()==EINTR);
1916 return result;
1917 #else
1918 RUDIMENTS_SET_ENOSYS
1919 return -1;
1920 #endif
1921 }
1922