1 /* datei.cc
2 * This file belongs to Worker, a file manager for UN*X/X11.
3 * Copyright (C) 2001-2020 Ralf Hoffmann.
4 * You can contact me at: ralf@boomerangsworld.de
5 * or http://www.boomerangsworld.de/worker
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "datei.h"
23 #include "aguix/lowlevelfunc.h"
24 #include "wconfig.h"
25 #include "grouphash.h"
26 #include "aguix/mutex.h"
27 #include "aguix/utf8.hh"
28 #include "nwc_os.hh"
29 #include "nwc_path.hh"
30 #include "worker.h"
31
Datei()32 Datei::Datei()
33 {
34 fd = -1;
35 error=0;
36 iseof = false;
37
38 sectiondepth = 0;
39 }
40
~Datei()41 Datei::~Datei()
42 {
43 if ( fd >= 0 ) close();
44 }
45
open(const char * name,const char * mode)46 int Datei::open( const char *name, const char *mode )
47 {
48 int m;
49 mode_t p;
50
51 if ( name == NULL ) return 1;
52 if ( mode == NULL ) return 1;
53
54 if ( strlen( mode ) < 1 ) return 1; // wrong mode
55
56 //TODO: Currently "b" in mode will fail open in any case
57
58 p = 0;
59 if ( strcasecmp( mode, "r" ) == 0 ) {
60 m = O_RDONLY;
61 } else if ( strcasecmp( mode, "r+" ) == 0 ) {
62 m = O_RDWR;
63 } else if ( strcasecmp( mode, "w" ) == 0 ) {
64 m = O_WRONLY | O_CREAT | O_TRUNC;
65 p = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
66 } else if ( strcasecmp( mode, "w+" ) == 0 ) {
67 m = O_RDWR | O_CREAT | O_TRUNC;
68 p = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
69 } else if ( strcasecmp( mode, "a" ) == 0 ) {
70 m = O_WRONLY | O_CREAT | O_APPEND;
71 p = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
72 } else if ( strcasecmp( mode, "a+" ) == 0 ) {
73 m = O_RDWR | O_CREAT | O_APPEND;
74 p = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
75 } else {
76 return 1;
77 }
78
79 p = p & ~Worker::getUMask();
80
81 fd = ::worker_open( name, m, p );
82 if ( fd < 0 ) return 1;
83 iseof = false;
84 return 0;
85 }
86
close()87 int Datei::close()
88 {
89 int res = -1;
90
91 if ( fd < 0 ) return res;
92 res = ::worker_close( fd );
93 fd = -1;
94 iseof = false;
95
96 if ( res != 0 ) error++;
97 return res;
98 }
99
putUChar(unsigned char value)100 int Datei::putUChar(unsigned char value)
101 {
102 if ( fd < 0 ) return -1;
103 int x;
104 x = putCharacter( value );
105 if(x!=EOF) return 1;
106 return 0;
107 }
108
putUShort(unsigned short int value)109 int Datei::putUShort(unsigned short int value)
110 {
111 if ( fd < 0 ) return -1;
112 int x;
113 x = putCharacter( value >> 8 );
114 if(x==EOF) return 0;
115 x = putCharacter( value & 0xff );
116 if(x==EOF) return 1;
117 return 2;
118 }
119
putInt(int value)120 int Datei::putInt(int value)
121 {
122 if ( fd < 0 ) return -1;
123 int x,tv;
124 if(value<0) {
125 x = putCharacter( 1 );
126 if(x==EOF) return 0;
127 } else {
128 x = putCharacter( 0 );
129 if(x==EOF) return 0;
130 }
131 tv=abs(value);
132 int i;
133 for(i=0;i<4;i++) {
134 x = putCharacter( tv & 0xff );
135 if(x==EOF) return i+1;
136 tv>>=8;
137 }
138 return i+1;
139 }
140
getInt()141 int Datei::getInt()
142 {
143 if ( fd < 0 ) return -1;
144 int vz,x,value;
145 vz = getCharacter();
146 if(vz<0) {
147 error++;
148 return 0;
149 }
150 value=0;
151 for(int i=0;i<4;i++) {
152 x = getCharacter();
153 if(x==EOF) {
154 error++;
155 return 0;
156 }
157 value+=(x<<(8*i));
158 }
159 if(vz==1) value*=-1;
160 return value;
161 }
162
putULong(unsigned long value)163 int Datei::putULong(unsigned long value)
164 {
165 if ( fd < 0 ) return -1;
166 int x;
167 x = putCharacter( ( value & 0xff000000 ) >> 24 );
168 if(x==EOF) return 0;
169 x = putCharacter( ( value & 0xff0000 ) >> 16 );
170 if(x==EOF) return 1;
171 x = putCharacter( ( value & 0xff00 ) >> 8 );
172 if(x==EOF) return 2;
173 x = putCharacter( value & 0xff );
174 if(x==EOF) return 3;
175 return 4;
176 }
177
putString(const char * str1)178 int Datei::putString( const char *str1 )
179 {
180 int x, l;
181
182 if ( fd < 0 ) return -1;
183 if ( str1 == NULL ) return -1;
184
185 l = strlen( str1 );
186 x = worker_write( fd, str1, l );
187 if ( x < 0 ) {
188 error++;
189 return -2;
190 } else if ( x != l ) {
191 error++;
192 }
193 return x;
194 }
195
getUChar()196 unsigned char Datei::getUChar()
197 {
198 if ( fd < 0 ) {
199 error++;
200 return 0;
201 }
202 int x;
203 x = getCharacter();
204 if(x==EOF) {
205 error++;
206 return 0;
207 }
208 return (unsigned char) x;
209 }
210
getCharAsInt()211 int Datei::getCharAsInt()
212 {
213 if ( fd < 0 ) {
214 error++;
215 return 0;
216 }
217 return getCharacter();
218 }
219
getUShort()220 unsigned short Datei::getUShort()
221 {
222 if ( fd < 0 ) {
223 error++;
224 return 0;
225 }
226 int x;
227 unsigned short int a;
228 x = getCharacter();
229 if(x==EOF) {
230 error++;
231 return 0;
232 }
233 a=((unsigned int)x)*0x100;
234 x = getCharacter();
235 if(x==EOF) {
236 error++;
237 return 1;
238 }
239 a+=(unsigned int)x;
240 return a;
241 }
242
getULong()243 unsigned long Datei::getULong()
244 {
245 if ( fd < 0 ) {
246 error++;
247 return 0;
248 }
249 int x;
250 unsigned long a;
251 x = getCharacter();
252 if(x==EOF) {
253 error++;
254 return 0;
255 }
256 a=((unsigned int)x)*0x1000000;
257 x = getCharacter();
258 if(x==EOF) {
259 error++;
260 return 1;
261 }
262 a+=((unsigned int)x)*0x10000;
263 x = getCharacter();
264 if(x==EOF) {
265 error++;
266 return 2;
267 }
268 a+=((unsigned int)x)*0x100;
269 x = getCharacter();
270 if(x==EOF) {
271 error++;
272 return 3;
273 }
274 a+=(unsigned int)x;
275 return a;
276 }
277
getString(int count)278 char *Datei::getString(int count)
279 {
280 if ( fd < 0 ) return NULL;
281 unsigned char *tstr,*tstr2;
282 int ch;
283 long x;
284 long size;
285 if(count==-1) {
286 /* lesen bis NULL-Byte */
287 size=1024;
288 tstr=(unsigned char*)_allocsafe(size);
289 x=0;
290 do {
291 ch = getCharacter();
292 if(ch!=EOF) {
293 tstr[x++]=(unsigned char)ch;
294 } else {
295 tstr[x++]=0;
296 break;
297 }
298 if(x==size) {
299 size*=2;
300 tstr2=(unsigned char*)_allocsafe(size);
301 if(tstr2==NULL) break;
302 strcpy((char*)tstr2,(char*)tstr);
303 _freesafe(tstr);
304 tstr=tstr2;
305 }
306 } while(ch!=0);
307 } else {
308 tstr=(unsigned char*)_allocsafe(count+1);
309 if(tstr!=NULL) {
310 for(x=0;x<count;x++) {
311 ch = getCharacter();
312 tstr[x]=(unsigned char)ch;
313 }
314 tstr[count]=0;
315 }
316 }
317 return (char*)tstr;
318 }
319
getString(char * buf,int count)320 int Datei::getString(char *buf,int count)
321 {
322 buf[0]=0;
323 char *str=getString(count);
324 strncpy(buf,str,count);
325 buf[count]=0;
326 _freesafe(str);
327 return strlen(buf);
328 }
329
fileExists(const char * name)330 bool Datei::fileExists(const char *name)
331 {
332 worker_struct_stat stbuf;
333 if ( worker_lstat( name, &stbuf ) != 0 ) return false;
334 else {
335 /* kann auch verzeichnis sein */
336 // if(S_ISDIR(stbuf.st_mode)) return false;
337 }
338 return true;
339 }
340
fileExistsExt(const char * name)341 Datei::d_fe_t Datei::fileExistsExt(const char*name)
342 {
343 worker_struct_stat stbuf;
344 d_fe_t return_value;
345 if ( worker_stat( name, &stbuf ) != 0 ) return_value = D_FE_NOFILE;
346 else {
347 if(S_ISDIR(stbuf.st_mode)) return_value=D_FE_DIR;
348 else return_value=D_FE_FILE;
349 if(S_ISLNK(stbuf.st_mode)) return_value=D_FE_LINK;
350 }
351 return return_value;
352 }
353
lfileExistsExt(const char * name)354 Datei::d_fe_t Datei::lfileExistsExt(const char*name)
355 {
356 worker_struct_stat stbuf;
357 d_fe_t return_value;
358 if ( worker_lstat( name, &stbuf ) != 0 ) return_value = D_FE_NOFILE;
359 else {
360 if(S_ISDIR(stbuf.st_mode)) return_value=D_FE_DIR;
361 else return_value=D_FE_FILE;
362 if(S_ISLNK(stbuf.st_mode)) return_value=D_FE_LINK;
363 }
364 return return_value;
365 }
366
seek(long offset,int mode)367 void Datei::seek(long offset,int mode)
368 {
369 if ( fd >= 0 ) worker_lseek( fd, offset, mode );
370 }
371
getOwnerStringLen(uid_t user,gid_t gr)372 int getOwnerStringLen(uid_t user,gid_t gr)
373 {
374 char *tstr;
375 #ifdef DEBUG
376 // printf("entering getOwnerStringLen\n");
377 #endif
378 int len=0;
379 int ost=wconfig->getOwnerstringtype();
380 #ifdef DEBUG
381 // printf(" getUserNameS\n");
382 #endif
383 tstr=ugdb->getUserNameS(user);
384 if(tstr!=NULL) len+=strlen(tstr);
385 len+=(ost==1)?1:3;
386 #ifdef DEBUG
387 // printf(" getGroupNameS\n");
388 #endif
389 tstr=ugdb->getGroupNameS(gr);
390 if(tstr!=NULL) len+=strlen(tstr);
391 #ifdef DEBUG
392 // printf("leaving getOwnerStringLen\n");
393 #endif
394 return len;
395 }
396
getOwnerString(uid_t user,gid_t mygroup)397 char* getOwnerString(uid_t user,gid_t mygroup)
398 {
399 int len=0;
400 char *tstr1,*tstr2;
401 int ost=wconfig->getOwnerstringtype();
402
403 tstr1=ugdb->getUserNameS(user);
404 tstr2=ugdb->getGroupNameS(mygroup);
405 if(tstr1!=NULL) len+=strlen(tstr1);
406 len+=(ost==1)?1:3;
407 if(tstr2!=NULL) len+=strlen(tstr2);
408 char *str=(char*)_allocsafe((len+2)*sizeof(char));
409 str[0]=0;
410 if(tstr1!=NULL) strcat(str,tstr1);
411 strcat(str,(ost==1)?".":" @ ");
412 if(tstr2!=NULL) strcat(str,tstr2);
413 return str;
414 }
415
overreadChunk()416 int Datei::overreadChunk()
417 {
418 int chunksize=getInt();
419 while(chunksize>0) {
420 getUChar();
421 chunksize--;
422 }
423 return 0;
424 }
425
getIntSize()426 int Datei::getIntSize()
427 {
428 return 5;
429 }
430
getUCharSize()431 int Datei::getUCharSize()
432 {
433 return 1;
434 }
435
getUShortSize()436 int Datei::getUShortSize()
437 {
438 return 2;
439 }
440
getULongSize()441 int Datei::getULongSize()
442 {
443 return 4;
444 }
445
errors()446 long Datei::errors()
447 {
448 long e=error;
449 error=0;
450 return e;
451 }
452
getFilenameFromPath(const char * path)453 char *Datei::getFilenameFromPath(const char*path)
454 {
455 char *tstr;
456 int pos;
457 if(path==NULL) return NULL;
458 pos=strlen(path)-2; // -2 because a name contains min. 1 character
459 // but it can be a slash so skiping it
460 while(pos>=0) {
461 if(path[pos]=='/') break;
462 pos--;
463 }
464 if(pos>=0) tstr=dupstring(&path[pos+1]);
465 else tstr=dupstring(path);
466 return tstr;
467 }
468
getNameWithoutExt(const char * name)469 char *Datei::getNameWithoutExt(const char *name)
470 {
471 char *tstr;
472 int pos,len;
473 bool found=false;
474 if(name==NULL) return NULL;
475 len=strlen(name);
476 pos=len-1;
477 while(pos>=0) {
478 if((name[pos]=='/')&&(pos<(len-1))) break;
479 if(name[pos]=='.') {
480 found=true;
481 break;
482 }
483 pos--;
484 }
485 if(found==false) tstr=dupstring(name);
486 else {
487 tstr=(char*)_allocsafe(pos+1);
488 if(pos>0) strncpy(tstr,name,pos);
489 tstr[pos]=0;
490 }
491 return tstr;
492 }
493
494 /**
495 * function returns name of tmp file in user's worker directory
496 * file will be created
497 * It can however return NULL if after a certain number of
498 * retries no tmp file couldn't be created
499 * THREADSAFE
500 */
createTMPName(const char * infix,const char * suffix)501 char *Datei::createTMPName( const char *infix,
502 const char *suffix )
503 {
504 char *returnstr = NULL, buffer[ 2 * A_BYTESFORNUMBER( int ) ];
505 int rannr;
506 static int lfdnr = 0;
507 int tfd;
508 static MutEx lock;
509
510 if ( infix == NULL ) infix = "";
511 if ( suffix == NULL ) suffix = "";
512
513 lock.lock();
514 for( int retry = 0; retry < 1000; retry++ ) {
515 rannr=rand();
516 sprintf( buffer, "%d%d", lfdnr++, rannr );
517 returnstr = (char*)_allocsafe( strlen( worker_tmpdir() ) +
518 strlen( "/worker" ) +
519 strlen( infix ) + strlen( buffer ) +
520 strlen( suffix ) + 1 );
521 sprintf( returnstr, "%s/worker%s%s%s", worker_tmpdir(), infix, buffer, suffix );
522 if(Datei::lfileExistsExt(returnstr)==Datei::D_FE_NOFILE) {
523 tfd = ::worker_open( returnstr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR );
524 if ( tfd >= 0 ) {
525 ::worker_close( tfd );
526 worker_chmod( returnstr, S_IRUSR | S_IWUSR );
527 break;
528 }
529 }
530 _freesafe(returnstr);
531 returnstr = NULL;
532 }
533 lock.unlock();
534 return returnstr;
535 }
536
createTMPHardlink(const std::string & name)537 std::string Datei::createTMPHardlink( const std::string &name )
538 {
539 std::string returnstr;
540 int rannr;
541 static int lfdnr = 0;
542 static MutEx lock;
543
544 lock.lock();
545
546 for( int retry = 0; retry < 1000; retry++ ) {
547 rannr = rand();
548
549 returnstr = AGUIXUtils::formatStringToString( "%s/workerlnk%s%d%d",
550 worker_tmpdir(),
551 "",
552 lfdnr++, rannr );
553 if ( Datei::lfileExistsExt( returnstr.c_str() ) == Datei::D_FE_NOFILE ) {
554 if ( worker_link( name.c_str(),
555 returnstr.c_str() ) == 0 ) {
556 break;
557 } else {
558 if ( errno != EEXIST ) {
559 returnstr = "";
560 break;
561 }
562 }
563 }
564 returnstr = "";
565 }
566
567 lock.unlock();
568
569 return returnstr;
570 }
571
putStringExt(const char * format,const char * str)572 int Datei::putStringExt(const char *format,const char *str)
573 {
574 int written, size;
575 char *tstr;
576
577 if ( fd < 0 ) return -1;
578 if ( format == NULL ) return -1;
579 if ( str == NULL ) return -1;
580
581 size = strlen( format ) + strlen( str ) + 1;
582 tstr = (char*)_allocsafe( size );
583 while ( 1 ) {
584 written = snprintf( tstr, size, format, str );
585 if ( ( written > -1 ) && ( written < size ) ) break;
586
587 //TODO: in case of an error we try to use more space
588 // but if for whatever reason does not work at all
589 // we should perhaps not end the program (because)
590 // alloc will fail) but only quit this function
591 size *= 2;
592 _freesafe( tstr );
593 tstr = (char*)_allocsafe( size );
594 }
595 putString( tstr );
596 _freesafe( tstr );
597 return 0;
598 }
599
shrinkFilename(const char * str,int maxlength,AWidth & lencalc)600 char *Datei::shrinkFilename( const char *str, int maxlength, AWidth &lencalc )
601 {
602 char *tstr = NULL;
603 int len, len1;
604 bool stopnow;
605 const char *lastl, *lastr, *startl, *startr, *str1;
606 const char *filename;
607 int dddlen;
608 int l1, l2, l3, real_width;
609 std::string tstr1;
610
611 if ( str == NULL )
612 return NULL;
613
614 // test if the str will fit in maxlength
615 len = strlen( str );
616 if( ( lencalc.getWidth( str, len ) <= maxlength ) || ( len <= 5 ) )
617 return dupstring( str );
618
619 dddlen = lencalc.getWidth( "..." );
620
621 // now we really have to do something
622
623 // first find the most important part, the filename
624 // we will also take the beginning slash (if exists) to show the user
625 // the filename is not shorten
626 // first test: is there any slash
627 // if not then shorten the str with lowlevelfunc shrinkstring
628 // if:
629 // filename starts at the last slash or the next to last
630 // if the str ends with a slash
631 // if this is longer then maxlength-5 (atleast 2 chars at the beginning and "...")
632 // then just do a shringstring because the filename will be shorten in any case
633 // otherwise:
634 // find the first dirname from left
635 // if it will fit into the string, add it
636 // otherwise take the previous string and stop
637 // do the same with the first dirname from right
638 // specialcase: filename is shorter then maxlength-5
639 // but the first dir doesnt fit, then use as much chars from it
640 // to fill maxlength
641
642 int right_pos = len; // this is the 0 byte
643 UTF8::movePosToPrevChar( str, right_pos ); // to last character
644 UTF8::movePosToPrevChar( str, right_pos ); /* to skip a final / (if exists)
645 since a filename is atleast 1 char this would
646 point in the worst case at the beginning slash */
647 str1 = str + right_pos;
648
649 // now search for the slash backwards
650
651 while ( *str1 != '/' ) {
652 str1--;
653 if ( str1 < str ) break;
654 }
655
656 if ( str1 < str ) {
657 // no slash (or only a final one)
658 return shrinkstring( str, maxlength, lencalc );
659 } else {
660 // found filename
661 // we will also take the slash into it
662 filename = str1;
663
664 if ( lencalc.getWidth( filename ) + lencalc.getWidth( "/.../" ) > maxlength )
665 return shrinkstring( str, maxlength, lencalc );
666
667 // enough room for some additional chars
668 startl = str;
669 startr = filename;
670 lastl = str; // this are the last positions that will fit into maxlength
671 lastr = filename;
672
673 if ( startl[0] == '/' ) // starting slash => skip
674 startl++;
675
676 // startr is at the start filename and so points to a slash
677 // but because we want to prefer the first dir from left, leave it so
678
679 for ( stopnow = false; ; ) {
680 // remember: there is a slash before the filename
681 // so this will stop there (or before)
682 while ( *startl != '/' ) {
683 startl++;
684 }
685 // this could run over the left
686 while ( *startr != '/' ) {
687 startr--;
688 if ( startr < str ) break;
689 }
690
691 if ( startl > startr ) {
692 // since startr is before startl both found the same mid dir
693 // this dir will not fit in maxlength because then everything would fit
694 // but this cannot be because of previous checks
695 // just take lastl und lastr to build new string
696 stopnow = true;
697 } else {
698 // test if startl and/or startr will fit
699 // otherwise stop
700
701 // get the number of bytes up to including startl
702 right_pos = startl - str;
703 UTF8::movePosToNextChar( str, right_pos );
704 len1 = right_pos;
705 /* len1 is actually ( startl - str + 1 ) since startl
706 points to the slash but this it's generic
707 the same goes for the next two lastl calculations */
708
709 l1 = lencalc.getWidth( str, len1 );
710 l2 = lencalc.getWidth( lastr );
711
712 if ( ( l1 + dddlen + l2 ) <= maxlength ) {
713 // new dir at the left will fit
714 lastl = startl;
715 }
716
717 // get the number of bytes up to including lastl
718 right_pos = lastl - str;
719 UTF8::movePosToNextChar( str, right_pos );
720 len1 = right_pos;
721
722 l1 = lencalc.getWidth( str, len1 );
723 l2 = lencalc.getWidth( startr );
724
725 if ( ( l1 + dddlen + l2 ) <= maxlength ) {
726 // new dir at the right will fit
727 lastr = startr;
728 }
729
730 if ( ( lastl != startl ) && ( lastr != startr ) ) {
731 // nothing has changed so stop
732 stopnow = true;
733 }
734 }
735
736 if ( stopnow == true ) {
737 // time to stop
738 if ( lastl == str ) {
739 // no fitting dirs found
740 // so take as much as possibly
741
742 l1 = lencalc.getWidth( filename );
743 l1 += dddlen;
744 l2 = maxlength - l1;
745
746 if ( l2 > 0 ) {
747 l3 = lencalc.getStrlen4Width( str, l2, &real_width );
748
749 tstr1 = "";
750 tstr1.append( str, l3 );
751 tstr1 += "...";
752 tstr1 += filename;
753 tstr = dupstring( tstr1.c_str() );
754 } else {
755 tstr = shrinkstring( str, maxlength, lencalc );
756 }
757 } else {
758 // get the number of bytes up to including lastl
759 right_pos = lastl - str;
760 UTF8::movePosToNextChar( str, right_pos );
761 len1 = right_pos;
762
763 tstr1 = "";
764 tstr1.append( str, len1 );
765 tstr1 += "...";
766 tstr1 += lastr;
767 if ( lencalc.getWidth( tstr1.c_str() ) > maxlength ) {
768 tstr = shrinkstring( str, maxlength, lencalc );
769 } else {
770 tstr = dupstring( tstr1.c_str() );
771 }
772 }
773 break;
774 }
775
776 startl++;
777 startr--;
778 }
779 }
780
781 return tstr;
782 }
783
putLine(const char * str)784 int Datei::putLine( const char *str )
785 {
786 int x, y, l;
787
788 if ( str == NULL ) return -1;
789 if ( fd < 0 ) return -1;
790
791 l = strlen( str );
792 x = worker_write( fd, str, l );
793 if ( x < 0 ) {
794 error++;
795 return -2;
796 } else if ( x != l ) {
797 error++;
798 }
799
800 y = worker_write( fd, "\n", 1 );
801 if ( y < 0 ) {
802 error++;
803 return -2;
804 } else if ( y != 1 ) {
805 error++;
806 }
807
808 return x + y;
809 }
810
getLine()811 char *Datei::getLine()
812 {
813 if ( fd < 0 ) return NULL;
814 unsigned char *tstr,*tstr2;
815 int ch;
816 long x;
817 long size;
818
819 size=1024;
820 tstr = (unsigned char*)_allocsafe( size );
821 x = 0;
822 do {
823 ch = getCharacter();
824 if ( ch != EOF ) {
825 tstr[ x++ ] = (unsigned char)ch;
826 } else {
827 tstr[ x++ ] = 0;
828 break;
829 }
830 if ( x == size ) {
831 size *= 2;
832 tstr2 = (unsigned char*)_allocsafe( size );
833 if ( tstr2 == NULL ) break;
834 memcpy( (char*)tstr2, (char*)tstr, x );
835 _freesafe( tstr );
836 tstr = tstr2;
837 }
838 } while ( ( ch != 0 ) && ( ch != '\n' ) );
839 if ( tstr[ x - 1 ] == '\n' ) tstr[ x - 1 ] = '\0';
840 return (char*)tstr;
841 }
842
isEOF()843 bool Datei::isEOF()
844 {
845 if ( fd < 0 ) return true;
846 return iseof;
847 }
848
fileSize(const char * name)849 loff_t Datei::fileSize( const char *name )
850 {
851 worker_struct_stat stbuf;
852 loff_t return_value;
853
854 if ( worker_stat( name, &stbuf ) != 0 ) return_value = -1;
855 else {
856 return_value = stbuf.st_size;
857 }
858 return return_value;
859 }
860
861 /*
862 * getRelativePath
863 *
864 * will return relative path for source in destdir
865 * in other words: destdir/returnvalue will be the same fileentry
866 * as source
867 */
getRelativePath(const char * source,const char * destdir,bool use_realpath)868 char *Datei::getRelativePath( const char *source, const char *destdir, bool use_realpath )
869 {
870 int startpos, curpos, mode, i;
871 char *mysource, *mydestdir;
872 std::string erg;
873
874 if ( ( source == NULL ) || ( destdir == NULL ) ) return NULL;
875
876 /* basicly it works this way:
877 first remove same directories from the beginning
878 then for each directory in destdir add ".." before the source
879
880 because this code cannot handle .. and . in the paths
881 I remove them with HandlePath
882 It's not a big deal to handle these strings too (by ignoring
883 "." and removing an added "../" for ".." but this way this function
884 keeps small and clean :-)
885 */
886
887 if ( use_realpath ) {
888 mysource = NWC::Path::handlePath( source );
889 mydestdir = NWC::Path::handlePath( NWC::Path::get_real_path( destdir ).c_str() );
890
891 std::string real_destdir = NWC::Path::get_real_path( destdir );
892 if ( real_destdir.empty() ) {
893 mydestdir = NWC::Path::handlePath( destdir );
894 } else {
895 mydestdir = NWC::Path::handlePath( real_destdir.c_str() );
896 }
897 } else {
898 mysource = NWC::Path::handlePath( source );
899 mydestdir = NWC::Path::handlePath( destdir );
900 }
901
902 for ( i = strlen( mysource ) - 1; i >= 0; i-- ) {
903 if ( mysource[i] == '/' ) mysource[i] = '\0';
904 else break;
905 }
906 for ( i = strlen( mydestdir ) - 1; i >= 0; i-- ) {
907 if ( mydestdir[i] == '/' ) mydestdir[i] = '\0';
908 else break;
909 }
910
911 if ( ( strlen( mysource ) < 1 ) || ( strlen( mydestdir ) < 1 ) ) {
912 _freesafe( mysource );
913 _freesafe( mydestdir );
914 return NULL;
915 }
916
917 startpos = curpos = 0;
918 erg = "";
919 mode = 0;
920
921 // I just parse mydestdir and add "../" for every /
922 // but because I want to remove same basedir
923 // I will also parse the source string
924 for (;;) {
925 // the end of mydestdir is the only way to break this loop
926 if ( mydestdir[curpos] == '\0' ) {
927 // add "../" because destdir is a dir (as the name says)
928 // then add the rest of mysource
929 #if 0
930 // this code is correct!
931 // but it will create results the user
932 // doesn't expect (because it's too complicated)
933 // for example
934 // linking /tmp/file1 into /tmp would
935 // would result in ../tmp/file1 which is 100%
936 // correct but the user expect just file1 as
937 // relative path and that's what the #else part
938 // checks
939 erg += "../";
940 erg += &mysource[startpos];
941 #else
942 if ( ( mode == 0 ) && ( mysource[ curpos ] == '/' ) ) {
943 // mydestdir ended but we are still in "same character" mode
944 // and the source also ends as an dir so there is no need
945 // for any "../"
946 // read the above comment !
947 erg += &mysource[ curpos + 1 ];
948 } else {
949 erg += "../";
950 erg += &mysource[startpos];
951 }
952 #endif
953 break;
954 }
955 switch ( mode ) {
956 case 1:
957 if ( mydestdir[ curpos++ ] == '/' ) {
958 erg += "../";
959 }
960 break;
961 default:
962 if ( mysource[ curpos ] == '\0' ) mode = 1; // no curpos change!
963 else if ( ( mysource[ curpos ] == '/' ) &&
964 ( mydestdir[ curpos ] == '/' ) ) {
965 // new directory, old one was identically
966 // so set new start
967 startpos = ++curpos;
968 } else if ( mysource[ curpos ] == mydestdir[ curpos ] ) {
969 // same character => keep in this mode
970 curpos++;
971 } else mode = 1; // no cursorchange
972 break;
973 }
974 }
975 _freesafe( mysource );
976 _freesafe( mydestdir );
977 if ( erg.length() < 1 ) return NULL;
978 return dupstring( erg.c_str() );
979 }
980
getRelativePathExt(const char * source,const char * destdir,bool use_realpath)981 char *Datei::getRelativePathExt( const char *source,
982 const char *destdir,
983 bool use_realpath )
984 {
985 char *erg[2] = { NULL, NULL };
986
987 if ( ! source || ! destdir ) return NULL;
988
989 erg[0] = getRelativePath( source, destdir, use_realpath );
990 if ( erg[0] == NULL ) {
991 return NULL;
992 }
993
994 if ( use_realpath ) {
995 std::string real_source = NWC::Path::get_real_path( source );
996 if ( ! real_source.empty() ) {
997 erg[1] = getRelativePath( real_source.c_str(),
998 destdir,
999 use_realpath );
1000 }
1001 }
1002
1003 if ( erg[1] == NULL ) {
1004 return erg[0];
1005 }
1006
1007 // if the relative path for the real_source is shorter, take this one
1008 if ( strlen( erg[1] ) < strlen( erg[0] ) ) {
1009 _freesafe( erg[0] );
1010 return erg[1];
1011 }
1012
1013 _freesafe( erg[1] );
1014 return erg[0];
1015 }
1016
putCharacter(int c)1017 int Datei::putCharacter( int c )
1018 {
1019 unsigned char cf[1];
1020 int count;
1021
1022 if ( fd < 0 ) return EOF;
1023
1024 cf[0] = (unsigned char)c;
1025
1026 count = worker_write( fd, cf, 1 );
1027 if ( count < 1 ) {
1028 error++;
1029 return EOF;
1030 }
1031 return cf[0];
1032 }
1033
getCharacter()1034 int Datei::getCharacter()
1035 {
1036 unsigned char cf[1];
1037 int count;
1038
1039 if ( fd < 0 ) return EOF;
1040
1041 count = ::worker_read( fd, cf, 1 );
1042
1043 if ( count < 1 ) {
1044 iseof = true;
1045 return EOF;
1046 }
1047 return (int)( cf[0] );
1048 }
1049
copyfile(const char * dest,const char * source,CopyfileProgressCallback * progress_callback)1050 int Datei::copyfile( const char *dest, const char *source,
1051 CopyfileProgressCallback *progress_callback )
1052 {
1053 int fdw,fdr;
1054 bool useregcopy, cancel, follow_symlinks, isCorrupt;
1055 ssize_t readbytes,writebytes;
1056 #define BUFSIZE ( 4 * 1024 )
1057 char *buf[BUFSIZE];
1058 worker_struct_stat st, dst;
1059 int erg;
1060 loff_t total_bytes = 0, bytes_copied = 0;
1061
1062 if ( ( dest == NULL ) || ( source == NULL ) ) return 1;
1063
1064 follow_symlinks = false;
1065 isCorrupt = false;
1066 cancel = false;
1067
1068 // get stat for file
1069 if ( worker_lstat( source, &st ) != 0 ) return 1;
1070
1071 // get stat for destination if link (will fail for corrupt links)
1072 // but currently I don't handle them anyway
1073 if ( worker_stat( source, &dst ) != 0 ) return 1;
1074
1075 useregcopy = false;
1076 if ( S_ISREG( st.st_mode ) ) {
1077 useregcopy = true;
1078 total_bytes = st.st_size;
1079 } else if ( ( S_ISLNK( st.st_mode ) ) &&
1080 ( follow_symlinks == true ) &&
1081 ( isCorrupt == false ) &&
1082 ( S_ISREG( dst.st_mode ) ) ) {
1083 useregcopy = true;
1084 total_bytes = dst.st_size;
1085 }
1086
1087 if ( useregcopy == false ) return 1;
1088
1089 fdr = ::worker_open( source, O_RDONLY, 0 );
1090 if ( fdr == -1 ) {
1091 // can't open inputfile
1092 return 1;
1093 }
1094
1095 fdw = ::worker_open( dest, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR );
1096 if ( fdw == -1 ) {
1097 ::worker_close( fdr );
1098 return 1;
1099 }
1100
1101 writebytes = -1;
1102 erg = 0;
1103 do {
1104 readbytes = ::worker_read( fdr, buf, BUFSIZE );
1105 if ( readbytes < 0 ) {
1106 // error while reading
1107 erg = 1;
1108 break;
1109 } else if ( readbytes == 0 ) {
1110 break;
1111 } else {
1112 writebytes = worker_write( fdw, buf, readbytes );
1113 if ( writebytes != readbytes ) {
1114 // something went wrong
1115 erg = 1;
1116 break;
1117 }
1118
1119 bytes_copied += writebytes;
1120
1121 if ( progress_callback != NULL ) {
1122 progress_callback->progress_callback( bytes_copied,
1123 total_bytes );
1124 }
1125 }
1126 } while ( ( readbytes > 0 ) &&
1127 ( cancel == false ) );
1128
1129 ::worker_close( fdr );
1130 if ( ::worker_close( fdw ) != 0 ) {
1131 // error while closing -> incomplete copy
1132 erg = 1;
1133 }
1134 return erg;
1135 #undef BUFSIZE
1136 }
1137
configPutPair(const char * id,const char * info)1138 void Datei::configPutPair( const char *id, const char *info )
1139 {
1140 std::string str1;
1141 int x;
1142
1143 if ( ( id == NULL ) || ( info == NULL ) ) return;
1144 str1 = "";
1145 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1146 str1 += id;
1147 str1 += " = ";
1148 str1 += info;
1149 str1 += ";";
1150 putLine( str1.c_str() );
1151 }
1152
configPutPairNum(const char * id,int num)1153 void Datei::configPutPairNum( const char *id, int num )
1154 {
1155 std::string str1;
1156 char buf[A_BYTESFORNUMBER( int )];
1157 int x;
1158
1159 if ( id == NULL ) return;
1160 str1 = "";
1161 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1162 sprintf( buf, "%d", num );
1163 str1 += id;
1164 str1 += " = ";
1165 str1 += buf;
1166 str1 += ";";
1167 putLine( str1.c_str() );
1168 }
1169
configPutPairNum(const char * id,int num1,int num2)1170 void Datei::configPutPairNum( const char *id, int num1, int num2 )
1171 {
1172 std::string str1;
1173 char buf[A_BYTESFORNUMBER( int )];
1174 int x;
1175
1176 if ( id == NULL ) return;
1177 str1 = "";
1178 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1179 sprintf( buf, "%d", num1 );
1180 str1 += id;
1181 str1 += " = ";
1182 str1 += buf;
1183 str1 += ",";
1184 sprintf( buf, "%d", num2 );
1185 str1 += buf;
1186 str1 += ";";
1187 putLine( str1.c_str() );
1188 }
1189
configPutPairString(const char * id,const char * str,bool escape_newlines)1190 void Datei::configPutPairString( const char *id, const char *str, bool escape_newlines )
1191 {
1192 std::string str1;
1193 char *buf;
1194 int i, o;
1195 int x;
1196
1197 if ( ( id == NULL ) || ( str == NULL ) ) return;
1198 str1 = "";
1199 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1200
1201 buf = (char*)_allocsafe( strlen( str ) * 2 + 1 );
1202 for ( i = 0, o = 0; i < (int)strlen( str ); i++ ) {
1203 if ( str[i] == '"' ) {
1204 buf[o++] = '\\';
1205 buf[o++] = '"';
1206 } else if ( str[i] == '\\' ) {
1207 buf[o++] = '\\';
1208 buf[o++] = '\\';
1209 } else if ( str[i] == '\n' ) {
1210 if ( escape_newlines ) {
1211 buf[o++] = '\\';
1212 buf[o++] = '\n';
1213 }
1214 } else {
1215 buf[o++] = str[i];
1216 }
1217 }
1218 buf[o] = '\0';
1219 str1 += id;
1220 str1 += " = \"";
1221 str1 += buf;
1222 str1 += "\";";
1223 _freesafe( buf );
1224 putLine( str1.c_str() );
1225 }
1226
configPutPairBool(const char * id,bool val)1227 void Datei::configPutPairBool( const char *id, bool val )
1228 {
1229 std::string str1;
1230 int x;
1231
1232 if ( id == NULL ) return;
1233 str1 = "";
1234 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1235
1236 str1 += id;
1237 str1 += " = ";
1238 str1 += ( ( val == true ) ? "true" : "false" );
1239 str1 += ";";
1240 putLine( str1.c_str() );
1241 }
1242
configPutInfo(const char * str,bool semicolon)1243 void Datei::configPutInfo( const char *str, bool semicolon )
1244 {
1245 std::string str1;
1246 int x;
1247
1248 if ( str == NULL ) return;
1249 str1 = "";
1250 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1251
1252 str1 += str;
1253 if ( semicolon == true ) str1 += ";";
1254 putLine( str1.c_str() );
1255 }
1256
configPutString(const char * str,bool semicolon,bool escape_newlines)1257 void Datei::configPutString( const char *str, bool semicolon, bool escape_newlines )
1258 {
1259 std::string str1;
1260 char *buf;
1261 int i, o;
1262 int x;
1263
1264 if ( str == NULL ) return;
1265 str1 = "";
1266 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1267
1268 buf = (char*)_allocsafe( strlen( str ) * 2 + 1 );
1269 for ( i = 0, o = 0; i < (int)strlen( str ); i++ ) {
1270 if ( str[i] == '"' ) {
1271 buf[o++] = '\\';
1272 buf[o++] = '"';
1273 } else if ( str[i] == '\\' ) {
1274 buf[o++] = '\\';
1275 buf[o++] = '\\';
1276 } else if ( str[i] == '\n' ) {
1277 if ( escape_newlines ) {
1278 buf[o++] = '\\';
1279 buf[o++] = '\n';
1280 }
1281 } else {
1282 buf[o++] = str[i];
1283 }
1284 }
1285 buf[o] = '\0';
1286 str1 += "\"";
1287 str1 += buf;
1288 str1 += "\";";
1289 _freesafe( buf );
1290 putLine( str1.c_str() );
1291 }
1292
configOpenSection(const char * sectioname)1293 void Datei::configOpenSection( const char *sectioname )
1294 {
1295 int x;
1296 std::string str1;
1297
1298 if ( sectioname == NULL ) return;
1299 if ( ( sectiondepth < 0 ) || ( sectiondepth > 100 ) ) sectiondepth = 0;
1300
1301 str1 = "";
1302 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1303
1304 str1 += sectioname;
1305 str1 += " {";
1306 putLine( str1.c_str() );
1307 sectiondepth++;
1308 }
1309
configCloseSection()1310 void Datei::configCloseSection()
1311 {
1312 int x;
1313 std::string str1;
1314
1315 sectiondepth--;
1316 if ( ( sectiondepth < 0 ) || ( sectiondepth > 100 ) ) sectiondepth = 0;
1317
1318 str1 = "";
1319 for ( x = 0; x < sectiondepth; x++ ) str1 += "\t";
1320
1321 str1 += "}";
1322 putLine( str1.c_str() );
1323 }
1324
read(char * buffer,size_t len)1325 ssize_t Datei::read( char *buffer, size_t len )
1326 {
1327 if ( buffer == NULL || len < 1 ) return 0;
1328 if ( fd < 0 ) return 0;
1329
1330 ssize_t count;
1331
1332 count = ::worker_read( fd, buffer, len );
1333
1334 if ( count < 1 ) {
1335 iseof = true;
1336 }
1337 return count;
1338 }
1339
~CopyfileProgressCallback()1340 CopyfileProgressCallback::~CopyfileProgressCallback()
1341 {
1342 }
1343