Prev: Reading /proc/<pid>/maps
Next: Code and Creation 73169
From: Jan Seiffert on 4 Feb 2010 05:41 frank schrieb: [snip] > Here's what I have now: > [snip] > > /* Open the given directory, if we can. */ > dir = opendir (theDir); > if (dir == NULL) { > fprintf (stderr, "Error opening %s: %s\n", theDir, strerror (errno)); > return 0; > } > > dirlen = strlen(theDir); > for( retval = readdir_r (dir, &entry, &entryPtr); entryPtr != NULL; > retval = readdir_r (dir, &entry, &entryPtr)) { > struct stat entryInfo; > > if (!strcmp (entry.d_name, ".") || !strcmp (entry.d_name, "..") ) > continue; > namelen = strlen(entry.d_name); > > if (dirlen+1+namelen+1 >= sizeof pathName) { > fprintf(stderr,"Name too long: %u+1+%u+1 %s/%s\n" > , (unsigned) dirlen, (unsigned) namelen,theDir,entry.d_name ); > continue; } > memcpy (pathName, theDir, dirlen); > pathName[dirlen] = '/'; > memcpy (pathName+dirlen+1, entry.d_name, namelen +1); > > if (lstat (pathName, &entryInfo) == -1) { /* stat() failed, let's > party */ > fprintf (stderr, "Error statting %s: %s\n", pathName, strerror > (errno)); continue; } > I don't know how portable you want to get, but you can save yourself this copying (at first) with fstatat: if(fstatat(dir, entry.d_name, &entryInfo, AT_SYMLINK_NOFOLLOW)) { fprintf(stderr, "stat'ing file \"%s/%s\": %s\n", theDir, entry.d_name, strerror(errno)); continue; } This way you can easier malloc (and free) the string at the right places and loose the length restriction (and use less stack space, which can be important in deeply nested trees). > count++; You are incrementing count before you know you will add it to your array > if (S_ISDIR (entryInfo.st_mode)) { /* directory */ > printf ("processing %s/\n", pathName); > > continue; } you are supposed to call yourself recursively here > if (S_ISREG (entryInfo.st_mode)) { /* regular file */ > printf ("\t%s has %lld bytes\n" > , pathName, (long long) entryInfo.st_size); > continue; } > if (S_ISLNK (entryInfo.st_mode)) { /* symbolic link */ > char targetName[PATH_SIZE + 1]; > if (readlink (pathName, targetName, PATH_SIZE) == -1) { > printf ("\t%s -> (invalid symbolic link!)\n", pathName); > continue; } > printf ("\t%s -> %s\n", pathName, targetName); > continue; } > printf ("\t%s (Strange Mode: 0x%x)\n", pathName, entryInfo.st_mode); > } > > /* Close the directory and return the number of entries. */ > (void) closedir (dir); > return count; array and numfiles is untouched. You return the count and not some error value... > } > > > > int main(int argc, char **argv) > { > char **array = NULL; > > int numFiles; > int index; > int error; > > if(argc > 1) > { > error = process_directory(argv[1], &array, &numFiles); > switch(error) ... which interacts badly with your main() > { > case 0: > for(index = 0; index < numFiles; index++) > { > printf("%s\n", array[index]); > } > > FreeStrArray(array, numFiles); > break; > case ERR_STRING_NOT_RESIZED: You return the count of processed files from process_directory, not some error... > case ERR_ALLOC_FAILED: > case ERR_FILES_NOT_ADDED: > puts("Insufficient memory."); ... so your print about insufficient memory is bogus. > break; > case ERR_PATH_OPEN_FAILED: > printf("Couldn't open %s for reading\n", argv[1]); > break; > default: > printf("Unknown error! Code %d.\n", error); > break; and whats under case 0 should be here. Since most errors come from an system function anyway you can save yourself returning an error number: #include <stdbool.h> bool process_directory() { if(...) return false; return true; } if(processes_directory(....)) { } else { perror("processing directories"); } [snip] > > // gcc -D_GNU_SOURCE -Wall -Wextra string2.o moi2.c -o out > dan(a)dan-desktop:~/source/unleashed/ch11$ > And if you do not use those string2 foo, you can leave it out. > 1) How do I populate Array in process_directory() instead of populating > stdout? Either with you string2 foo if its that good, or yeah, with malloc, remalloc, and the string functions. But i would not use an array for that, instead a linked list, saves you the 3-star programming and reallocations. If you really want an array, you can transform the list to an array afterward, but then you will know how many entries you will need etc. [snip] Greetings Jan -- assert(!"The excrement has collided with the air circulation device");
From: frank on 5 Feb 2010 01:03 Jan Seiffert wrote: [lots of code, so big snips] No. I don't want to recurse through. I may not have said that succinctly that but do so now. > But i would not use an array for that, instead a linked list, saves you the > 3-star programming and reallocations. If you really want an array, you can > transform the list to an array afterward, but then you will know how many > entries you will need etc. Jan, my statement about realloc is that if a person has to use it, he turns out to be wrong. CBFalconer made a career out of being serially wrong. Even Heathfield has had to eat his humble pie with realloc. Do I want to jump ship right now to something else: dan(a)dan-desktop:~/source/unleashed/ch11$ gcc -c -D_GNU_SOURCE -Wall -Wextra sllist.c -o ll1.o dan(a)dan-desktop:~/source/unleashed/ch11$ ls C11_001.c c11_015.c deque.h ll1.c~ rd3.c strarr.c~ C11_002.c C11_016.c dequemn.c ll1.o readme.txt strarr.h C11_003.c c11_017.c dllist.c moi1.c sllist.c string2.o C11_004.c c11_018.c dllisteg.c moi1.c~ sllist.c~ string.o C11_005.c c11_019.c dllist.h moi2.c sllist.h t1.c C11_006.c c11_020.c dllistmn.c moi2.c~ sllistmn.c t1.c~ C11_007.c c11_021.c foo.o out stack.c t2.c C11_008.c c11_022.c heap.c queue.c stack.h t2.c~ C11_009.c cityloc.txt heap.h queue.h stackmn.c t3.c C11_010.c clist.c heapmn.c queuemn.c strarr2.c text1.txt C11_011.c clist.h k r1.c strarr2.c~ tu1.c C11_012.c clistmn2.c kenny1.c r1.c~ strarr2.h tu1.o C11_013.c clistmn.c kenny1.c~ r2.c strarr2.h~ C11_014.c deque.c ll1.c r2.c~ strarr.c dan(a)dan-desktop:~/source/unleashed/ch11$ gcc ll1.o -D_GNU_SOURCE -Wall -Wextra ll1.c -o out dan(a)dan-desktop:~/source/unleashed/ch11$ ./out Read UNIX Unleashed, by Burk and Horvath. Read Builder Unleashed, by Calvert. Read C: How to Program, by Deitel & Deitel. Read DOS Programmers Reference, by Dettmann & Johnson. Read C : A Reference Manual, by Harbison & Steele. Read C Unleashed, by Heathfield & Kirby. Read Linux Unleashed, by Husain and Parker. Read C Programming Language, by Kernighan & Ritchie. Read Data Structures & Algorithms, by Lafore. Read C++ Unleashed, by Liberty. Read The Standard C Library, by Plauger. Read Teach Yourself BCB, by Reisdorph. Read Algorithms in C, by Sedgewick. Read C++ Programming Language, by Stroustrup. Read C Programming FAQs, by Summit. Read Expert C Programming, by van der Linden. dan(a)dan-desktop:~/source/unleashed/ch11$ cat sllist.h /* sllist.h - header for single linked list lib * * SLLIST - Single-Linked List Library * * Copyright (C) 2000 Richard Heathfield * Eton Computer Systems Ltd * Macmillan Computer Publishing * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General * Public License along with this program; if not, write * to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. * * Richard Heathfield may be contacted by email at: * binary(a)eton.powernet.co.uk * */ #ifndef SLLIST_H__ #define SLLIST_H__ #define SL_SUCCESS 0 #define SL_NO_MEM 1 #define SL_ZERO_SIZE 2 typedef struct SLLIST { int Tag; struct SLLIST *Next; void *Object; size_t Size; } SLLIST; /* Add new item immediately after current item */ int SLAdd(SLLIST **Item, int Tag, void *Object, size_t Size); /* Add item to front of list. Care: if you pass * this function any node other than the first, * you will get Y-branches in your list: * * oldroot-->- * \ * >->-passeditem-->-->--oldnext * / * newitem-->- * * This would be a Bad Thing. */ int SLFront(SLLIST **Item, int Tag, void *Object, size_t Size); /* Add new item right at the end of the list */ int SLAppend(SLLIST **Item, int Tag, void *Object, size_t Size); /* Replace existing data */ int SLUpdate(SLLIST *Item, int NewTag, void *NewObject, size_t NewSize); /* Retrieve data from this node */ void *SLGetData(SLLIST *Item, int *Tag, size_t *Size); /* Delete this item. Returns pointer to * next item - caller's responsibility * to maintain list integrity. */ SLLIST *SLDeleteThis(SLLIST *Item); /* Delete item immediately following * the one passed in. List integrity * maintained automatically. */ void SLDeleteNext(SLLIST *Item); /* Destroy the entire list */ void SLDestroy(SLLIST **List); /* Call func(Tag, ThisItem, Args) for each item */ int SLWalk(SLLIST *List, int(*Func)(int, void *, void *), void *Args); #endif dan(a)dan-desktop:~/source/unleashed/ch11$ cat sllist.c /* sllist.c - source for single linked list lib * * SLLIST - Single-Linked List Library * * Copyright (C) 2000 Richard Heathfield * Eton Computer Systems Ltd * Macmillan Computer Publishing * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General * Public License along with this program; if not, write * to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. * * Richard Heathfield may be contacted by email at: * binary(a)eton.powernet.co.uk * */ #include <stdlib.h> #include <string.h> #include <assert.h> #include "sllist.h" int SLAdd(SLLIST **Item, int Tag, void *Object, size_t Size) { SLLIST *NewItem; int Result = SL_SUCCESS; assert(Item != NULL); if(Size > 0) { NewItem = malloc(sizeof *NewItem); if(NewItem != NULL) { NewItem->Tag = Tag; NewItem->Size = Size; NewItem->Object = malloc(Size); if(NewItem->Object != NULL) { memcpy(NewItem->Object, Object, Size); /* Handle empty list */ if(NULL == *Item) { NewItem->Next = NULL; *Item = NewItem; } else /* Insert just after current item */ { NewItem->Next = (*Item)->Next; (*Item)->Next = NewItem; } } else { free(NewItem); Result = SL_NO_MEM; } } else { Result = SL_NO_MEM; } } else { Result = SL_ZERO_SIZE; } return Result; } int SLFront(SLLIST **Item, int Tag, void *Object, size_t Size) { int Result = SL_SUCCESS; SLLIST *p = NULL; assert(Item != NULL); Result = SLAdd(&p, Tag, Object, Size); if(SL_SUCCESS == Result) { p->Next = *Item; *Item = p; } return Result; } int SLAppend(SLLIST **Item, int Tag, void *Object, size_t Size) { int Result = SL_SUCCESS; SLLIST *EndSeeker; assert(Item != NULL); if(NULL == *Item) { Result = SLAdd(Item, Tag, Object, Size); } else { EndSeeker = *Item; while(EndSeeker->Next != NULL) { EndSeeker = EndSeeker->Next; } Result = SLAdd(&EndSeeker, Tag, Object, Size); } return Result; } int SLUpdate(SLLIST *Item, int NewTag, void *NewObject, size_t NewSize) { int Result = SL_SUCCESS; void *p; if(NewSize > 0) { p = realloc(Item->Object, NewSize); if(NULL != p) { Item->Object = p; memmove(Item->Object, NewObject, NewSize); Item->Tag = NewTag; Item->Size = NewSize; } else { Result = SL_NO_MEM; } } else { Result = SL_ZERO_SIZE; } return Result; } void *SLGetData(SLLIST *Item, int *Tag, size_t *Size) { void *p = NULL; if(Item != NULL) { if(Tag != NULL) { *Tag = Item->Tag; } if(Size != NULL) { *Size = Item->Size; } p = Item->Object; } return p; } SLLIST *SLDeleteThis(SLLIST *Item) { SLLIST *NextNode = NULL; if(Item != NULL) { NextNode = Item->Next; if(Item->Object != NULL) { free(Item->Object); } free(Item); } return NextNode; } void SLDeleteNext(SLLIST *Item) { if(Item != NULL && Item->Next != NULL) { Item->Next = SLDeleteThis(Item->Next); } } void SLDestroy(SLLIST **List) { SLLIST *Next; if(*List != NULL) { Next = *List; do { Next = SLDeleteThis(Next); } while(Next != NULL); *List = NULL; } } int SLWalk(SLLIST *List, int(*Func)(int, void *, void *), void *Args) { SLLIST *ThisItem; int Result = 0; for(ThisItem = List; 0 == Result && ThisItem != NULL; ThisItem = ThisItem->Next) { Result = (*Func)(ThisItem->Tag, ThisItem->Object, Args); } return Result; } /* end of sllist.c */ // gcc -c -D_GNU_SOURCE -Wall -Wextra sllist.c -o ll1.o dan(a)dan-desktop:~/source/unleashed/ch11$ One other question here. Does Unix Unleashed exist? -- frank
From: Phred Phungus on 5 Feb 2010 02:08 Pascal J. Bourguignon wrote: > frank <frank(a)example.invalid> writes: > >> Pascal J. Bourguignon wrote: >>> frank <frank(a)example.invalid> writes: >>>> So, are there any more than than these possibilities for entry.d_name: >>>> 1) . >>>> 2) .. >>>> 3) directory >>>> 4) regular file >>>> 5) link >>>> ? >>> NAME_MAX >>> Yes. There are about Σ 254^i - 5 other possibilities for entry.d_name. >>> 1 >>> (all the byte values are possible in d_name, but 0 and 47, and >>> d_name >>> may be any length from 1 to NAME_MAX). >>> On my system, where NAME_MAX is 255, that makes: >>> 17151848561775 >>> 524542260230899909345527623287683809220880277204575135673770 >>> 350790616073358738754853669771246761598037707765815012818953 >>> 935481259985629589001894465990514560016269745315761470342905 >>> 916427583379787162454198607651001112150892505697618658680722 >>> 340651617534533646250823154025408246347525049252624268535973 >>> 202331185548752849740059467645750723512718885190900684145962 >>> 332212188080108626733451568195673134215363122237241696148086 >>> 390170981092766227408226801240032059729007827039773745754612 >>> 965254102893844749238702970926320276892692441496131912435884 >>> 815683131626478581446738498427741257604636279796430784947109 >> Thx, Pascal, I think I've got enough fingers and toes to count out the >> possibilities there. :) >> >> I wouldn't mind seeing the source for this calculation. > > NAME_MAX > The source is: Σ 254^i - 5 > i=1 > > The compiled form is: (- (loop for i from 1 to 255 sum (expt 254 i)) 5) But the number is larger than long long max and outputted appropriately for usenet. If you don't want to post your source, that's fine, but why hide a buschel? > > >> How would '...' be interpreted by stat? > > stat(2) doesn't interpret anything, and "..." is a perfectly valid > name for any directory entry. > > [pjb(a)galatea :0.0 tmp]$ touch ... > [pjb(a)galatea :0.0 tmp]$ ls -l ... > -rw-r--r-- 1 pjb wheel 0 Jan 31 01:21 ... > [pjb(a)galatea :0.0 tmp]$ rm ... > [pjb(a)galatea :0.0 tmp]$ sudo mknod ... b 1 2 > Password: > [pjb(a)galatea :0.0 tmp]$ ls -l ... > brw-r--r-- 1 root wheel 1, 2 Jan 31 01:22 ... > [pjb(a)galatea :0.0 tmp]$ sudo rm ... > [pjb(a)galatea :0.0 tmp]$ # etc > I have close to no idea what you mean show there, but are you possibly a Galatian? -- Phred
From: Ben Bacarisse on 5 Feb 2010 09:24 Phred Phungus <Phred(a)example.invalid> writes: > Pascal J. Bourguignon wrote: >> frank <frank(a)example.invalid> writes: >> >>> Pascal J. Bourguignon wrote: >>>> frank <frank(a)example.invalid> writes: >>>>> So, are there any more than than these possibilities for entry.d_name: >>>>> 1) . >>>>> 2) .. >>>>> 3) directory >>>>> 4) regular file >>>>> 5) link >>>>> ? >>>> NAME_MAX >>>> Yes. There are about Σ 254^i - 5 other possibilities for entry.d_name. >>>> 1 >>>> (all the byte values are possible in d_name, but 0 and 47, and >>>> d_name >>>> may be any length from 1 to NAME_MAX). >>>> On my system, where NAME_MAX is 255, that makes: >>>> 17151848561775 >>>> 524542260230899909345527623287683809220880277204575135673770 >>>> 350790616073358738754853669771246761598037707765815012818953 >>>> 935481259985629589001894465990514560016269745315761470342905 >>>> 916427583379787162454198607651001112150892505697618658680722 >>>> 340651617534533646250823154025408246347525049252624268535973 >>>> 202331185548752849740059467645750723512718885190900684145962 >>>> 332212188080108626733451568195673134215363122237241696148086 >>>> 390170981092766227408226801240032059729007827039773745754612 >>>> 965254102893844749238702970926320276892692441496131912435884 >>>> 815683131626478581446738498427741257604636279796430784947109 >>> Thx, Pascal, I think I've got enough fingers and toes to count out the >>> possibilities there. :) >>> >>> I wouldn't mind seeing the source for this calculation. >> >> NAME_MAX >> The source is: Σ 254^i - 5 >> i=1 >> >> The compiled form is: (- (loop for i from 1 to 255 sum (expt 254 i)) 5) > > But the number is larger than long long max and outputted > appropriately for usenet. If you don't want to post your source, > that's fine, but why hide a buschel? (- (loop for i from 1 to 255 sum (expt 254 i)) 5) is what you call the source (it's Lisp). It is a program that calculates the value posted. Here is another (this time in Haskell): sum (map (254^) [1..255]) - 5 >>> How would '...' be interpreted by stat? >> >> stat(2) doesn't interpret anything, and "..." is a perfectly valid >> name for any directory entry. >> >> [pjb(a)galatea :0.0 tmp]$ touch ... >> [pjb(a)galatea :0.0 tmp]$ ls -l ... >> -rw-r--r-- 1 pjb wheel 0 Jan 31 01:21 ... >> [pjb(a)galatea :0.0 tmp]$ rm ... >> [pjb(a)galatea :0.0 tmp]$ sudo mknod ... b 1 2 >> Password: >> [pjb(a)galatea :0.0 tmp]$ ls -l ... >> brw-r--r-- 1 root wheel 1, 2 Jan 31 01:22 ... >> [pjb(a)galatea :0.0 tmp]$ sudo rm ... >> [pjb(a)galatea :0.0 tmp]$ # etc >> > > I have close to no idea what you mean show there, but are you possibly > a Galatian? All he is doing is showing that ... is a perfectly normal file name. -- Ben.
From: Pascal J. Bourguignon on 5 Feb 2010 16:05
Phred Phungus <Phred(a)example.invalid> writes: > Pascal J. Bourguignon wrote: >> frank <frank(a)example.invalid> writes: >> >>> Pascal J. Bourguignon wrote: >>>> frank <frank(a)example.invalid> writes: >>>>> So, are there any more than than these possibilities for entry.d_name: >>>>> 1) . >>>>> 2) .. >>>>> 3) directory >>>>> 4) regular file >>>>> 5) link >>>>> ? >>>> NAME_MAX >>>> Yes. There are about Σ 254^i - 5 other possibilities for entry..d_name. >>>> 1 >>>> (all the byte values are possible in d_name, but 0 and 47, and >>>> d_name >>>> may be any length from 1 to NAME_MAX). >>>> On my system, where NAME_MAX is 255, that makes: >>>> 17151848561775 >>>> 524542260230899909345527623287683809220880277204575135673770 >>>> 350790616073358738754853669771246761598037707765815012818953 >>>> 935481259985629589001894465990514560016269745315761470342905 >>>> 916427583379787162454198607651001112150892505697618658680722 >>>> 340651617534533646250823154025408246347525049252624268535973 >>>> 202331185548752849740059467645750723512718885190900684145962 >>>> 332212188080108626733451568195673134215363122237241696148086 >>>> 390170981092766227408226801240032059729007827039773745754612 >>>> 965254102893844749238702970926320276892692441496131912435884 >>>> 815683131626478581446738498427741257604636279796430784947109 >>> Thx, Pascal, I think I've got enough fingers and toes to count out the >>> possibilities there. :) >>> >>> I wouldn't mind seeing the source for this calculation. >> >> NAME_MAX >> The source is: Σ 254^i - 5 >> i=1 >> >> The compiled form is: (- (loop for i from 1 to 255 sum (expt 254 i)) 5) > > But the number is larger than long long max and outputted > appropriately for usenet. If you don't want to post your source, > that's fine, but why hide a buschel? I didn't hide anything. Some programming language are actually high level programming language, and use normal integer arithmetic, not modulo 2^w arithmetic. Specifically, I use Common Lisp (Scheme and other programming languages would do too). Here is the copy-and-paste of a real interaction with the Common Lisp environment: C/USER[1]> (expt 2 100) 1267650600228229401496703205376 C/USER[2]> (defun factorial (x) (if (< x 1) 1 (* x (factorial (- x 1))))) FACTORIAL C/USER[3]> (factorial 40) 815915283247897734345611269596115894272000000000 C/USER[4]> (/ 2 3) 2/3 Notice also that 2/3 is not 0, but 2/3. Also, notice that lisp is technology FIFTY years old, nothing from the other world. Where have you been in the last 50 years? >>> How would '...' be interpreted by stat? >> >> stat(2) doesn't interpret anything, and "..." is a perfectly valid >> name for any directory entry. >> >> [pjb(a)galatea :0.0 tmp]$ touch ... >> [pjb(a)galatea :0.0 tmp]$ ls -l ... >> -rw-r--r-- 1 pjb wheel 0 Jan 31 01:21 ... >> [pjb(a)galatea :0.0 tmp]$ rm ... >> [pjb(a)galatea :0.0 tmp]$ sudo mknod ... b 1 2 >> Password: >> [pjb(a)galatea :0.0 tmp]$ ls -l ... >> brw-r--r-- 1 root wheel 1, 2 Jan 31 01:22 ... >> [pjb(a)galatea :0.0 tmp]$ sudo rm ... >> [pjb(a)galatea :0.0 tmp]$ # etc >> > > I have close to no idea what you mean show there, but are you possibly > a Galatian? I've shown that a directory entry named '...' can be either a regular file (created with touch), a block device (created by mknod b) a character device (created by mknod c), or whatever else it can be. This is called unix, not Galatian, a simple operating system FOURTY years old (not precisely high tech). Where have you been in the last 40 years? ;-) -- __Pascal Bourguignon__ |