-rw-r--r-- | lib/Makefile.am | 1 | ||||
-rw-r--r-- | lib/util.cc | 127 |
2 files changed, 128 insertions, 0 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index a904569..7d44856 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am | |||
@@ -14,2 +14,3 @@ libkonforka_la_SOURCES = \ | |||
14 | exception.cc \ | 14 | exception.cc \ |
15 | util.cc \ | ||
15 | pointer_map.cc \ | 16 | pointer_map.cc \ |
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 | } | ||