-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | include/Makefile.am | 1 | ||||
-rw-r--r-- | include/konforka/util.h | 103 | ||||
-rw-r--r-- | lib/Makefile.am | 1 | ||||
-rw-r--r-- | lib/util.cc | 127 |
5 files changed, 233 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 96d9325..33d1a59 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -1,4 +1,4 @@ | |||
1 | AC_INIT([konforka], [0.0], [konforka-bugs@klever.net]) | 1 | AC_INIT([konforka], [0.0.1], [konforka-bugs@klever.net]) |
2 | AC_CONFIG_SRCDIR([include/konforka/exception.h]) | 2 | AC_CONFIG_SRCDIR([include/konforka/exception.h]) |
3 | AC_CONFIG_HEADER([config.h]) | 3 | AC_CONFIG_HEADER([config.h]) |
4 | AM_INIT_AUTOMAKE([dist-bzip2]) | 4 | AM_INIT_AUTOMAKE([dist-bzip2]) |
diff --git a/include/Makefile.am b/include/Makefile.am index 3e043d3..5fbf85e 100644 --- a/include/Makefile.am +++ b/include/Makefile.am | |||
@@ -6,6 +6,7 @@ endif | |||
6 | 6 | ||
7 | nobase_include_HEADERS = \ | 7 | nobase_include_HEADERS = \ |
8 | konforka/exception.h \ | 8 | konforka/exception.h \ |
9 | konforka/util.h \ | ||
9 | konforka/basic_wrapper.h konforka/responsible_wrapper.h \ | 10 | konforka/basic_wrapper.h konforka/responsible_wrapper.h \ |
10 | konforka/resource_pile.h \ | 11 | konforka/resource_pile.h \ |
11 | konforka/pointer_map.h \ | 12 | konforka/pointer_map.h \ |
diff --git a/include/konforka/util.h b/include/konforka/util.h new file mode 100644 index 0000000..c06edd9 --- a/dev/null +++ b/include/konforka/util.h | |||
@@ -0,0 +1,103 @@ | |||
1 | #ifndef __KONFORKA_UTIL_H | ||
2 | #define __KONFORKA_UTIL_H | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | #include <string> | ||
6 | #include <konforka/exception.h> | ||
7 | |||
8 | /** | ||
9 | * @file | ||
10 | * @brief miscellaneous utility stuff. | ||
11 | */ | ||
12 | |||
13 | /** | ||
14 | * @brief The main konforka namespace. | ||
15 | */ | ||
16 | namespace konforka { | ||
17 | using std::string; | ||
18 | |||
19 | class restricted_sequence_error : public konforka::exception { | ||
20 | public: | ||
21 | restricted_sequence_error(const string& fi,const string& fu,int l,const string& w) | ||
22 | : konforka::exception(fi,fu,l,w) { } | ||
23 | }; | ||
24 | |||
25 | /** | ||
26 | * normalize_path options enumeration. | ||
27 | * @see normalize_path() | ||
28 | */ | ||
29 | enum normalize_path_options { | ||
30 | /** | ||
31 | * Restrict the /../ sequence. | ||
32 | */ | ||
33 | restrict_dotdot = 1, | ||
34 | /** | ||
35 | * Strip out the leading slash. | ||
36 | */ | ||
37 | strip_leading_slash = 2, | ||
38 | /** | ||
39 | * Strip out the trailing slash. | ||
40 | */ | ||
41 | strip_trailing_slash = 4 | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * Normalize pathname by stripping duplicate slashes, etc. | ||
46 | * @param p the pathname. | ||
47 | * @param o options. | ||
48 | * @return the normalized path. | ||
49 | * @see normalize_path_options | ||
50 | * @todo TODO: document exceptions. | ||
51 | */ | ||
52 | string normalize_path(const string& p,int o=(restrict_dotdot|strip_trailing_slash)); | ||
53 | |||
54 | /** | ||
55 | * Extract the directory part of the filename. | ||
56 | * @param p the pathname. | ||
57 | * @return the directory part. | ||
58 | */ | ||
59 | string dir_name(const string& p); | ||
60 | |||
61 | class beyond_root_error : public konforka::exception { | ||
62 | public: | ||
63 | beyond_root_error(const string& fi,const string& fu,int l,const string& w) | ||
64 | : konforka::exception(fi,fu,l,w) { } | ||
65 | }; | ||
66 | |||
67 | /** | ||
68 | * combine_path options enumeration. | ||
69 | * @see combine_path() | ||
70 | */ | ||
71 | enum combine_path_options { | ||
72 | /** | ||
73 | * The origin is file. Otherwise it is directory. | ||
74 | */ | ||
75 | origin_is_file = 1, | ||
76 | /** | ||
77 | * Fail if we've gone up beyond root. | ||
78 | */ | ||
79 | fail_beyond_root = 2 | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * Combine path with the relative path. | ||
84 | * @param orig the origin. | ||
85 | * @param rel relative path to combine with. | ||
86 | * @param o options. | ||
87 | * @return the paths combined. | ||
88 | * @see combine_path_options | ||
89 | * @todo TODO: document exceptions. | ||
90 | */ | ||
91 | string combine_path(const string& orig,const string& rel,int o=origin_is_file); | ||
92 | |||
93 | /** | ||
94 | * Create directory and parent directories if needed. | ||
95 | * @param p the pathname. | ||
96 | * @param m mode value for the newly created directories. | ||
97 | */ | ||
98 | void make_path(const string& p,mode_t m); | ||
99 | |||
100 | } | ||
101 | |||
102 | /* vim:set ft=cpp: */ | ||
103 | #endif /* __KONFORKA_UTIL_H */ | ||
diff --git a/lib/Makefile.am b/lib/Makefile.am index a904569..7d44856 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am | |||
@@ -12,5 +12,6 @@ endif | |||
12 | 12 | ||
13 | libkonforka_la_SOURCES = \ | 13 | libkonforka_la_SOURCES = \ |
14 | exception.cc \ | 14 | exception.cc \ |
15 | util.cc \ | ||
15 | pointer_map.cc \ | 16 | pointer_map.cc \ |
16 | ${EXTRA_SOURCES} | 17 | ${EXTRA_SOURCES} |
diff --git a/lib/util.cc b/lib/util.cc new file mode 100644 index 0000000..74039c6 --- a/dev/null +++ b/lib/util.cc | |||
@@ -0,0 +1,127 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <sys/stat.h> | ||
3 | #include <konforka/util.h> | ||
4 | |||
5 | namespace konforka { | ||
6 | |||
7 | /* | ||
8 | * XXX: this code is borrowed from sitecing as is, although it should be optimized. | ||
9 | */ | ||
10 | |||
11 | string normalize_path(const string& p,int o) { | ||
12 | const char *s = p.c_str(); | ||
13 | if( s[0]=='.' && s[1]=='/' ) | ||
14 | s += 2; // skip leading './' | ||
15 | if(o&strip_leading_slash) | ||
16 | for(;(*s)=='/';s++); | ||
17 | string rv; | ||
18 | string::size_type notslash = 0; | ||
19 | for(;*s;s++) { | ||
20 | if(s[0]=='/') { | ||
21 | if(s[1]=='/') | ||
22 | continue; // skip duplicate slash | ||
23 | if(s[1]=='.' && s[2]=='/') { | ||
24 | // '/./' sequence encountered | ||
25 | s += 2; | ||
26 | continue; | ||
27 | } | ||
28 | } | ||
29 | if( | ||
30 | (o&restrict_dotdot) && ( | ||
31 | ( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' ) // '^../' | ||
32 | || | ||
33 | ( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]=='/' || s[3]==0) ) // '/../' or '/..$' | ||
34 | ) | ||
35 | ) | ||
36 | throw restricted_sequence_error(CODEPOINT,"restricted updir (..) sequence encountered"); | ||
37 | rv += *s; | ||
38 | if( (*s) !='/' ) | ||
39 | notslash = rv.length(); | ||
40 | } | ||
41 | if(!(o&strip_trailing_slash)) | ||
42 | notslash++; | ||
43 | if(notslash<rv.length()) | ||
44 | rv.erase(notslash); // XXX: does this operation have enough sense to be performed? | ||
45 | return rv; | ||
46 | } | ||
47 | |||
48 | string dir_name(const string& p) { | ||
49 | string::size_type sl = p.find_last_of('/'); | ||
50 | if(sl==string::npos) | ||
51 | return ""; // no slashes -- no dir. | ||
52 | string::size_type nosl = p.find_last_not_of('/',sl); | ||
53 | if(nosl==string::npos) | ||
54 | return ""; // only slashes -- no dir. | ||
55 | return p.substr(0,nosl+1); | ||
56 | } | ||
57 | |||
58 | string combine_path(const string& orig,const string& rel,int o) { | ||
59 | string r = normalize_path(rel,0); | ||
60 | if(r.empty()) { | ||
61 | // XXX: this behaviour is questionable. | ||
62 | return normalize_path( (o&origin_is_file)?dir_name(orig):orig, strip_leading_slash|restrict_dotdot|strip_trailing_slash); | ||
63 | } | ||
64 | string rv; | ||
65 | if(r[0]=='/') { | ||
66 | r.erase(0,1); | ||
67 | }else{ | ||
68 | rv = normalize_path( (o&origin_is_file)?dir_name(orig):orig, restrict_dotdot|strip_trailing_slash); | ||
69 | } | ||
70 | string::size_type lsl = rv.rfind('/'); | ||
71 | // iterate through slashes in relative path | ||
72 | for(string::size_type sl=r.find('/');sl!=string::npos;sl=r.find('/')) { | ||
73 | assert(sl!=0); // sure we don't start with '/' at this point | ||
74 | if(sl==1 && r[0]=='.') { // './' | ||
75 | r.erase(0,2); | ||
76 | }else if(sl==2 && r[0]=='.' && r[1]=='.') { // '../' | ||
77 | if(lsl==string::npos) { | ||
78 | if(rv.empty() && (o&fail_beyond_root)) | ||
79 | throw beyond_root_error(CODEPOINT,"went beyond root while combining path"); | ||
80 | rv.clear(); | ||
81 | }else{ | ||
82 | rv.erase(lsl); | ||
83 | lsl = rv.rfind('/'); | ||
84 | } | ||
85 | r.erase(0,3); | ||
86 | }else{ // 'something/' | ||
87 | lsl = rv.length(); | ||
88 | rv += '/'; | ||
89 | rv += r.substr(0,sl); | ||
90 | r.erase(0,sl+1); | ||
91 | } | ||
92 | } | ||
93 | if(r.empty()) | ||
94 | return rv+'/'; | ||
95 | if(r.length()==2 && r[0]=='.' && r[1]=='.') { | ||
96 | if(lsl==string::npos) { | ||
97 | if(rv.empty() && (o&fail_beyond_root)) | ||
98 | throw beyond_root_error(CODEPOINT,"went beyond root while combining path"); | ||
99 | return "/"; | ||
100 | }else{ | ||
101 | rv.erase(lsl+1); | ||
102 | return rv; | ||
103 | } | ||
104 | } | ||
105 | rv += '/'; | ||
106 | rv += r; | ||
107 | return rv; | ||
108 | } | ||
109 | |||
110 | void make_path(const string& p,mode_t m) { | ||
111 | struct stat st; | ||
112 | for(string::size_type sl=0;sl!=string::npos;sl=p.find('/',sl+1)) { | ||
113 | if(!sl) | ||
114 | continue; | ||
115 | string pp = p.substr(0,sl); | ||
116 | if(stat(pp.c_str(),&st) || !S_ISDIR(st.st_mode)) { | ||
117 | if(mkdir(pp.c_str(),m)) | ||
118 | throw konforka::system_error(CODEPOINT,"failed to mkdir()"); | ||
119 | } | ||
120 | } | ||
121 | if(stat(p.c_str(),&st) || !S_ISDIR(st.st_mode)) { | ||
122 | if(mkdir(p.c_str(),m)) | ||
123 | throw konforka::system_error(CODEPOINT,"failed to mkdir()"); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | } | ||