Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

320 lines
7.7 KiB

  1. package PPM::Config;
  2. use strict;
  3. use Data::Dumper;
  4. use File::Path;
  5. require YAML;
  6. $PPM::Config::VERSION = '3.00';
  7. sub new {
  8. my $class = shift;
  9. my $self = bless { }, ref($class) || $class;
  10. my $file = shift;
  11. $self->{DATA} = {};
  12. if (defined $file) {
  13. $self->loadfile($file, 'load');
  14. $self->setsave($file);
  15. }
  16. return $self;
  17. }
  18. sub config {
  19. my $o = shift;
  20. return wantarray ? %{$o->{DATA}} : $o->{DATA};
  21. }
  22. sub loadfile {
  23. my $o = shift;
  24. my $file = shift;
  25. my $action = shift;
  26. open(FILE, "< $file") || die "can't read $file: $!";
  27. my $str = do { local $/; <FILE> };
  28. my $dat = eval { YAML::deserialize($str) } || {};
  29. close(FILE) || die "can't close $file: $!";
  30. $o->load($dat, $action);
  31. $o;
  32. }
  33. sub load {
  34. my $o = shift;
  35. my $dat = shift;
  36. my $action = shift || 'load';
  37. if ($action eq 'load' or not exists $o->{DATA}) {
  38. $o->{DATA} = $dat;
  39. }
  40. else {
  41. $o->merge($dat);
  42. }
  43. $o;
  44. }
  45. sub setsave {
  46. my $o = shift;
  47. my $file = shift;
  48. $o->{autosave} = 1;
  49. $o->{file} = $file;
  50. $o;
  51. }
  52. sub save {
  53. my $o = shift;
  54. my $file = shift || $o->{file};
  55. open(FILE, "> $file") || die "can't write $file: $!";
  56. my $str = YAML::serialize($o->{DATA});
  57. print FILE $str;
  58. close(FILE) || die "can't close $file: $!";
  59. $o;
  60. }
  61. sub merge {
  62. my $o = shift;
  63. my $dat = shift;
  64. _merge(\$o->{DATA}, \$dat)
  65. if (defined $dat);
  66. $o;
  67. }
  68. sub DESTROY {
  69. my $o = shift;
  70. $o->save if $o->{autosave};
  71. }
  72. sub _merge {
  73. my ($old_ref, $new_ref) = @_;
  74. return unless defined $old_ref and defined $new_ref;
  75. my $r_old = ref($old_ref);
  76. my $r_new = ref($new_ref);
  77. return unless $r_old eq $r_new;
  78. if ($r_old eq 'SCALAR') {
  79. $$old_ref = $$new_ref;
  80. }
  81. elsif ($r_old eq 'REF') {
  82. my $old = $$old_ref;
  83. my $new = $$new_ref;
  84. $r_old = ref($old);
  85. $r_new = ref($new);
  86. return unless $r_old eq $r_new;
  87. if (ref($old) eq 'HASH') {
  88. for my $key (keys %$new) {
  89. if (exists $old->{$key} and
  90. defined $old->{$key} and
  91. defined $new->{$key}) {
  92. _merge(\$old->{$key}, \$new->{$key});
  93. }
  94. else {
  95. $old->{$key} = $new->{$key};
  96. }
  97. }
  98. }
  99. elsif (ref($old) eq 'ARRAY') {
  100. for my $item (@$new) {
  101. if (ref($item) eq '' and not grep { $item eq $_ } @$old) {
  102. push @$old, $item;
  103. }
  104. elsif(ref($item)) {
  105. push @$old, $item;
  106. }
  107. }
  108. }
  109. }
  110. }
  111. #=============================================================================
  112. # get_conf_dirs(): return a list of directories to search for config files.
  113. #=============================================================================
  114. use constant DELIM => $^O eq 'MSWin32' ? ';' : ':';
  115. use constant PATHSEP => $^O eq 'MSWin32' ? '\\' : '/';
  116. use constant KEYDIR => 'ActiveState';
  117. use constant KEYFILE => 'ActiveState.lic';
  118. use constant CONFDIR => 'PPM';
  119. use constant CONFIG_SUFFIX => '.cfg';
  120. use constant UNIX_SHARED_ROOT => '/usr/local/etc';
  121. sub mymkpath {
  122. my $path = shift;
  123. unless (-d $path) {
  124. mkpath($path);
  125. die "Couldn't create directory $path: $!"
  126. unless -d $path;
  127. }
  128. $path;
  129. }
  130. sub get_license_file {
  131. my $license_dir = licGetHomeDir();
  132. my $lic_file = join PATHSEP, $license_dir, KEYFILE;
  133. return $lic_file;
  134. }
  135. sub load_config_file {
  136. my $name = shift;
  137. my $mode = shift || 'rw'; # 'ro' for read-only.
  138. $name .= CONFIG_SUFFIX;
  139. my $conf = PPM::Config->new;
  140. # Load all config files in the "configuration path"
  141. my $userdir = $ENV{PPM3_shared_config}
  142. ? eval { get_shared_conf_dir() }
  143. : get_user_conf_dir();
  144. my $shrddir = eval { get_shared_conf_dir() };
  145. # try to open the user's config area first. if it doesn't exist, open the
  146. # shared area. If neither exist, return an empty config which will
  147. # auto-save to their user directory.
  148. my $userfile = join PATHSEP, $userdir, $name;
  149. my $shrdfile = join PATHSEP, $shrddir, $name;
  150. $conf->setsave($userfile) unless $mode eq 'ro';
  151. return $conf->loadfile($userfile)
  152. if (-f $userfile and not -f $shrdfile);
  153. return $conf->loadfile($shrdfile)
  154. if (-f $shrdfile and not -f $userfile);
  155. if (-f $userfile or -f $shrdfile) {
  156. my $s_mtime = (stat $shrdfile)[9];
  157. my $u_mtime = (stat $userfile)[9];
  158. $conf->loadfile($s_mtime > $u_mtime ? $shrdfile : $userfile);
  159. }
  160. return $conf;
  161. }
  162. # Returns the user's configuration directory. Note: throws an exception if the
  163. # directory doesn't exist and cannot be created.
  164. sub get_user_conf_dir {
  165. return mymkpath(join PATHSEP, licGetHomeDir(), CONFDIR);
  166. }
  167. # Returns the shared configuration directory. Note: throws no exception, but
  168. # the directory is not guaranteed to exist. Install scripts and such should be
  169. # sure to create this directory themselves.
  170. sub get_shared_conf_dir {
  171. return join PATHSEP, UNIX_SHARED_ROOT, KEYDIR, CONFDIR
  172. if $^O ne 'MSWin32';
  173. my ($R,%R);
  174. require Win32::TieRegistry;
  175. Win32::TieRegistry->import(TiedHash => \%R);
  176. bless do { $R = \%R }, "Win32::TieRegistry";
  177. $R->Delimiter('/');
  178. my $wkey = $R->{"HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/"};
  179. my $xkey = $wkey->{"CurrentVersion/Explorer/Shell Folders/"};
  180. my $shared_root = $xkey->{"/Common AppData"};
  181. return join PATHSEP, $shared_root, KEYDIR, CONFDIR;
  182. }
  183. sub get_conf_dirs {
  184. my @path;
  185. push @path, get_shared_conf_dir(), get_user_conf_dir();
  186. @path
  187. }
  188. #=============================================================================
  189. # licGetHomeDir(): copied and converted from the Licence_V8 code:
  190. #=============================================================================
  191. sub licGetHomeDir {
  192. my $dir;
  193. my ($env1, $env2);
  194. if ($^O eq 'MSWin32') {
  195. $env1 = $ENV{APPDATA};
  196. }
  197. unless ($env1) {
  198. $env1 = $ENV{HOME};
  199. }
  200. # On Linux & Solaris:
  201. if ($^O ne 'MSWin32') {
  202. unless ($env1) {
  203. $env1 = (getpwuid $<)[7]; # Try to get $ENV{HOME} the hard way
  204. }
  205. $dir = sprintf("%s/.%s", $env1, KEYDIR);
  206. }
  207. # On Windows:
  208. else {
  209. unless ($env1) {
  210. $env1 = $ENV{USERPROFILE};
  211. }
  212. unless ($env1) {
  213. $env1 = $ENV{HOMEDRIVE};
  214. $env2 = $ENV{HOMEPATH};
  215. }
  216. unless ($env1) {
  217. $env1 = $ENV{windir};
  218. }
  219. unless ($env1) {
  220. die ("Couldn't find HOME / USERPROFILE / HOMEDRIVE&HOMEPATH / windir");
  221. }
  222. $env2 ||= "";
  223. $dir = $env1 . $env2;
  224. $dir =~ s|/|\\|g;
  225. # Win32 _stat() doesn't like trailing backslashes, except for x:\
  226. while (length($dir) > 3 && substr($dir, -1) eq '\\') {
  227. chop($dir);
  228. }
  229. die ("Not a directory: $dir") unless -d $dir;
  230. $dir .= PATHSEP;
  231. $dir .= KEYDIR;
  232. }
  233. # Create it if it doesn't exist yet
  234. return mymkpath($dir);
  235. }
  236. unless (caller) {
  237. my $dat = join '', <DATA>;
  238. eval $dat;
  239. die $@ if $@;
  240. }
  241. __DATA__
  242. #line 80
  243. use Data::Dumper;
  244. open(FILE, '>orig.cfg') || die "can't write orig.cfg: $!";
  245. print FILE <<'END';
  246. case-sensitivity: 0
  247. history: @
  248. : 1
  249. : 2
  250. install-follow: 1
  251. install-force: 0
  252. repository: ActiveState Package Repository
  253. rough: %
  254. foggy: dew
  255. sunny: day
  256. target: Perl 01
  257. END
  258. close(FILE) || die "can't close orig.cfg: $!";
  259. open(FILE, ">orig2.cfg") || die "can't write orig2.cfg: $!";
  260. print FILE <<'END';
  261. foo: bar
  262. rough: %
  263. dark: stormy
  264. morning: evening
  265. foggy: day
  266. END
  267. close(FILE) || die "can't close orig2.cfg: $!";
  268. {
  269. my $n = PPM::Config->new('orig.cfg');
  270. $n->load('orig2.cfg', 'merge');
  271. $n->save('new.cfg');
  272. }
  273. print Dumper [PPM::Config::get_license_file()];
  274. print Dumper [PPM::Config::get_user_conf_dir()];
  275. print Dumper [PPM::Config::get_conf_dirs()];