filepath._pike
Go to the documentation of this file.
1 /* Copyright (C) 2000-2007 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * $Id: filepath.pike,v 1.3 2010/08/20 20:42:25 astra Exp $
18  */
19 inherit "/kernel/module";
20 inherit "/kernel/orb";
21 #include <macros.h>
22 #include <assert.h>
23 #include <database.h>
24 #include <classes.h>
25 #include <access.h>
26 #include <database.h>
27 #include <attributes.h>
28 //! This module represents an ORB which converts a given pathname to
29 //! an sTeam object by using the structure of environment/inventory or
30 //! vice versa.
31 //!
32 //! There are several different trees with the
33 //! roots "/", "~user" or "/home/user".
34 class filepath : public module,orb{
35 public:
36 
37 
38 
39 
40 
41 //#define FILEPATH_DEBUG
42 
43 #ifdef FILEPATH_DEBUG
44 #define DEBUG_FILEPATH(s,args...) werror(s+"\n",args)
45 #else
46 #define DEBUG_FILEPATH(s,args...)
47 #endif
48 
49 #define MODE_ANNOTATE 1
50 #define MODE_VERSION 2
51 
52 
53  object db_handle;
54  mapping mPathCache = ([ ]);
55 
56 /**
57  * Initialize the module. This time only the description attributes is set.
58  *
59  */
60 private:
61 void init_module()
62 {
63  set_attribute(OBJ_DESC,"This is the filepath object for simulating "+
64  "a filepath in steam. It works by traversing through rooms in rooms/"+
65  "containers in containers starting from the Users "+
66  "and Groups workrooms");
67 }
68 
69 public:
70 
71 void post_load_module() {
72  db_handle = _Database->get_db_handle();
73 }
74 
75 /**
76  * Convert a given path to ~ syntax to retrieve a user or a workarea.
77  *
78  * @param string path - the path to convert.
79  * @return user or workarea object or 0.
80  */
81 object get_tilde(string path)
82 {
83  string user;
84  object uid;
85 
86  DEBUG_FILEPATH("get_tilde("+path+")");
87  if ( sscanf(path, "~%ss workroom", user) > 0 )
88  {
89  object workroom;
90 
91  uid = MODULE_USERS->lookup(user);
92  if ( !objectp(uid) ) {
93  uid = MODULE_GROUPS->lookup(user);
94  if ( !objectp(uid) )
95  return 0;
96  workroom = uid->query_attribute(GROUP_WORKROOM);
97  }
98  else {
99  workroom = uid->query_attribute(USER_WORKROOM);
100  }
101  DEBUG_FILEPATH("Returning workroom="+workroom->get_object_id());
102  return workroom;
103  }
104  else if ( sscanf(path, "~%s", user) > 0 )
105  {
106  // object is the user
107  uid = MODULE_USERS->lookup(user);
108  if ( !objectp(uid) )
109  uid = MODULE_GROUPS->lookup(user);
110  return uid;
111  }
112  return 0;
113 }
114 
115 object get_annotation_on_obj(object obj, string name)
116 {
117  return obj->get_annotation_byid(name);
118 }
119 
120 object get_version_of_obj(object obj, string name)
121 {
122 }
123 
124 /**
125  * get_object_in_cont
126  *
127  * @param cont - the container
128  * @param obj_name - path to object name (only one token: container or object)
129  * @return the appropriate object in the container
130  * @see
131  */
132 object
133 get_object_in_cont(object cont, string obj_name)
134 {
135  object obj;
136 
137  DEBUG_FILEPATH("get_object_in_cont("+cont->get_identifier()+","+
138  obj_name+")");
139 
140  if ( !objectp(cont) )
141  return 0;
142  if ( strlen(obj_name) > 0 && obj_name[0] == '~' )
143  return get_tilde(obj_name);
144 
145  obj = cont->get_object_byname(obj_name);
146  return obj;
147 }
148 
149 /**
150  * Get an array of objects which represent the environment of the environment
151  * (and so on) of the given object.
152  *
153  * @param object obj - the object to retrieve the environment hierarchy for.
154  * @return array of objects which represent the path to environment = null.
155  */
156 array object_to_environment_path(object obj)
157 {
158  array objects = ({ });
159 
160  object current = obj;
161  object env = obj->get_environment();
162  while ( objectp(env) ) {
163  DEBUG_FILEPATH("object_to_environment_path: " + obj->query_attribute(OBJ_NAME));
164  objects = ({ env }) + objects;
165  current = env;
166  env = current->get_environment();
167  }
168  // check root object if it is a workroom
169  if ( stringp(check_tilde(current)) )
170  objects = ({ _Server->get_module("home") }) + objects;
171 
172  return objects;
173 }
174 
175 /**
176  * resolves a given path, by starting with container uid and
177  * traversing through the tree to find the appropriate object
178  *
179  * @param uid - the user logged in (for ~ syntax) or null
180  * @param path - path to an object
181  * @return the object
182  * @see object_to_path
183  * @see path_to_object
184  */
185 object resolve_path(string|object env, string path, void|int rs_links)
186 {
187  object obj;
188  int i, mode;
189 
190  if (!objectp(env) && !stringp(env)) {
191  env = MODULE_OBJECTS->lookup("rootroom");
192  if ( !objectp(env) ) {
193  FATAL("Root-Room is null on resolve_path()...");
194  return 0;
195  }
196  }
197  else if (objectp(env)) {
198  path = Stdio.append_path(object_to_filename(env), path);
199  }
200  else if (stringp(env)) {
201  path = Stdio.append_path(env, path);
202  }
203 
204  if ( !stringp(path) || strlen(path) == 0 || path == "/" ) {
205  if (objectp(env)) {
206  return env;
207  }
208  return path_to_object(env);
209  }
210 
211  if ( path[0] != '/' )
212  path = "/" + path;
213  if ( path[-1] == '/' )
214  path = path[..strlen(path)-2];
215 
216  // FIXME: why is there a db search done here? it matches objects on / that are otherwise expected to be found in env
217  if (objectp(db_handle)) {
218  mixed err = catch {
219  string query = "select ob_id from ob_data where ob_attr='OBJ_PATH' and ob_data='\""+db_handle->quote(path)+"\"'";
220  Sql.sql_result res = db_handle->big_query(query);
221  if (objectp(res) && res->num_rows() == 1) {
222  mixed row = res->fetch_row();
223  return find_object((int)row[0]);
224  }
225  };
226  if (err) {
227  FATAL("Error while resolving path: %O\n%O", err[0], err[1]);
228  }
229  }
230  path = Stdio.append_path(path, "");
231 
232  if (!objectp(env))
233  env = path_to_object(env);
234 
235  obj = env;
236  array tokens = path / "/";
237  for ( mode = 0, i = 1; i < sizeof(tokens); i++ ) {
238  string token = tokens[i];
239  if (!objectp(env) ) return 0;
240  switch(mode) {
241  case MODE_ANNOTATE:
242  env = get_annotation_on_obj(env, token);
243  break;
244  case MODE_VERSION:
245  env = get_version_of_obj(env, token);
246  break;
247  default:
248  env = get_object_in_cont(env, token);
249  }
250  if ( objectp(env) ) {
251  // if links should be resolved...
252  if ( rs_links ) {
253  if ( env->get_object_class() & CLASS_EXIT )
254  env = env->get_exit();
255  else if ( env->get_object_class() & CLASS_LINK )
256  env = env->get_link_object();
257  }
258  obj = env;
259  }
260  else if ( token == "annotations" ) {
261  mode = MODE_ANNOTATE;
262  env = obj; // fall back to object in annotate mode!
263  }
264  else if ( token == "versions" ) {
265  mode = MODE_VERSION;
266  env = obj;
267  }
268  }
269 }
270 
271 /**
272  * Resolve a path. The ~ syntax will be converted to user/path.
273  * additionally the __oid syntax is understood by this function.
274  *
275  * @param path - the path to convert to an object
276  * @return the resolved object or 0
277  * @see resolve_path
278  */
279 object path_to_object(string path, void|bool rs_links)
280 {
281  object obj;
282 
283  if ( !stringp(path) || strlen(path) == 0 )
284  return 0;
285 
286  obj = mPathCache[path];
287  if (objectp(obj) && obj->status()>=0 && obj->status() != PSTAT_DELETED) {
288  if (!stringp(obj->query_attribute(OBJ_PATH)) || obj->query_attribute(OBJ_PATH) == path) {
289  if (rs_links) {
290  if (objectp(obj)) {
291  if (obj->get_object_class() & CLASS_LINK)
292  obj = obj->get_link_object();
293  else if (obj->get_object_class() & CLASS_EXIT)
294  obj = obj->get_exit();
295  }
296  }
297  return obj;
298  }
299  m_delete(mPathCache, obj);
300  }
301 
302  DEBUG_FILEPATH("path_to_object("+path+")");
303  if ( strlen(path) > 0 && path[0] != '/' && !IS_SOCKET(CALLER) ) {
304  obj = resolve_path(CALLER->get_environment(), path, rs_links);
305  }
306  else {
307  obj = resolve_path(0, path, rs_links);
308  }
309  mPathCache[path] = obj;
310  return obj;
311 }
312 
313 /**
314  * Check if a given object is a groups workarea or a user workroom
315  * and return the appropriate path.
316  *
317  * @param object obj - the object to check.
318  * @return tilde path or "" or 0.
319  */
320 string|int check_tilde(object obj)
321 {
322  object creator, workroom;
323 
324  if ( obj->get_object_class() & CLASS_ROOM ) {
325  if ( obj == _ROOTROOM )
326  return "";
327  foreach ( indices(mVirtualPath), object module ) {
328  string vpath = module->contains_virtual(obj);
329  if ( stringp(vpath) )
330  return mVirtualPath[module] + vpath;
331  }
332 
333  object owner = obj->query_attribute(OBJ_OWNER);
334  if ( objectp(owner) )
335  creator = owner;
336  else
337  creator = obj->get_creator();
338 
339  if ( objectp(creator) ) {
340  if ( creator->get_object_class() & CLASS_USER )
341  workroom = creator->query_attribute(USER_WORKROOM);
342  else
343  workroom = creator->query_attribute(GROUP_WORKROOM);
344  }
345 
346  if ( creator->get_object_class() & CLASS_USER )
347  return "/home/"+creator->get_user_name();
348  else
349  return "/home/"+creator->get_identifier();
350  }
351  }
352  else if ( obj->get_object_class() & CLASS_USER ) {
353  return "/~"+obj->get_user_name();
354  }
355 
356  return 0;
357 }
358 
359 string annotation_object_to_path(object obj)
360 {
361  object annotated;
362  string path = "/";
363  string name = obj->get_object_id();
364 
365  object ann = obj->get_annotating();
366  if (objectp(ann) ) {
367  annotated = ann;
368  ann = ann->get_annotating();
369  }
370  while ( objectp(ann) ) {
371  path = "/" + name + path;
372  name = ann->get_object_id();
373  annotated = ann;
374  ann = ann->get_annotating();
375  }
376  if ( !objectp(annotated) )
377  return "/void/" + obj->get_object_id();
378  return object_to_filename(annotated) + "/annotations" + path;
379 }
380 
381 string calendar_object_to_path(object obj)
382 {
383  return "/calendar/";
384 }
385 
386 string version_object_to_path(object obj)
387 {
388  object version = obj->query_attribute(OBJ_VERSIONOF);
389  if (objectp(version->query_attribute(OBJ_VERSIONOF)))
390  return "/versionmismatch/"+ version->get_object_id() + "/";
391  return object_to_filename(version) + "/versions/";
392 }
393 
394 /**
395  * return the path equivalent to an object
396  *
397  * @param obj - the object
398  * @return converts the object to a path description
399  * @see path_to_object
400  */
401 string
402 object_to_path(object obj)
403 {
404  object env, last_env;
405  string path;
406  mixed name;
407  string workroom;
408 
409 
410  if ( !objectp(obj) )
411  return "";
412 
413  if (obj == _ROOTROOM)
414  return "/";
415 
416  /* traverse through the tree beginning with the object itself
417  * and following the environment structure */
418  env = obj->get_environment();
419  last_env = env;
420  if ( last_env == _ROOTROOM )
421  return "/";
422  else if ( objectp(env) )
423  env = env->get_environment();
424  else if ( objectp(obj->get_annotating()) )
425  return annotation_object_to_path(obj);
426  else if ( obj->get_object_class() & CLASS_CALENDAR )
427  return calendar_object_to_path(obj);
428  else if ( objectp(obj->query_attribute(OBJ_VERSIONOF)) )
429  return version_object_to_path(obj);
430  else
431  return "/void/";
432 
433  if ( stringp(workroom=check_tilde(last_env)) )
434  return workroom + "/";
435 
436  path = "/";
437 
438  while ( objectp(env) ) {
439  name = last_env->get_identifier();
440 
441  path = "/" + name + path;
442  last_env = env;
443  if ( stringp(workroom=check_tilde(env)) ) {
444  return workroom + path;
445  }
446  env = env->get_environment();
447  }
448  string tilde = check_tilde(last_env);
449  if ( !stringp(tilde) ) {
450  if ( last_env == _ROOTROOM )
451  return path;
452  return "/void/";
453  }
454  return tilde + path;
455 }
456 
457 string object_to_identifier(object obj)
458 {
459  if (obj->get_object_class() & CLASS_CALENDAR) {
460  object creator = obj->get_creator();
461  if ( objectp(creator) )
462  return creator->get_identifier();
463  }
464  if (objectp(obj->get_environment()))
465  return obj->get_identifier();
466  return obj->get_object_id();
467 }
468 
469 /**
470  * Return the whole path, including the filename, for the given object.
471  *
472  * @param obj - the object to get the filename
473  * @return the filename
474  */
475 string object_to_filename(object obj, void|int force)
476 {
477  if ( !objectp(obj) )
478  steam_error("Cannot resolve filename for non-object !");
479 
480  return "/";
481 
482  if ( !force ) {
483  string path = obj->query_attribute(OBJ_PATH);
484  if ( stringp(path) && strlen(path) > 0 )
485  return path;
486  }
487 
488  string workroom;
489  if ( stringp(workroom=check_tilde(obj)) )
490  return workroom;
491  return object_to_path(obj) + object_to_identifier(obj);
492 }
493 
494 /**
495  * Get the Container or Room a given url-object is located.
496  *
497  * @param string url - the url to find the objects environment.
498  * @return the environment.
499  */
500 object
501 path_to_environment(string url)
502 {
503  int i;
504 
505  i = strlen(url) - 1;
506  while ( i > 0 && url[i] != '/' ) i--;
507  if ( i == 0 ) return _ROOTROOM;
508  return path_to_object(url[..i]);
509 }
510 
511 string get_identifier() { return "filepath:tree"; }
512 
513 /**
514  * Check whether the current user is able to read the given file.
515  *
516  * @param string file - the file to check.
517  * @return 0 or 1.
518  */
519 int check_access(string file)
520 {
521  object obj;
522  obj = path_to_object(file);
523  if ( objectp(obj) ) {
524  mixed err = catch {
525  _SECURITY->access_read(0, obj, this_user());
526  };
527  if ( arrayp(err) ) return 0;
528  DEBUG_FILEPATH("Access ok !");
529  return 1;
530  }
531  return 0;
532 }
533 
534 
535 
536 
537 };