root/vowfsc/db.c

Revision 55, 27.0 kB (checked in by nlawren2, 5 months ago)

Committed, and dead

Line 
1 #include "db.h"
2
3 #define DEBUG
4
5 #include "db-util.h"
6
7 // Begin fuction implementation
8 char *db_normalize_dir_name( char *dir_name ){
9         // Linked list structure
10         typedef struct list list;
11         struct list{
12                 char  *dir_name;
13                 int    str_len;
14                 list *next;
15                 list *prev;
16         };
17
18         list *temp, *list_tail, *list_head;
19         list_tail=list_head=malloc(sizeof(list));
20         list_tail->dir_name=dir_name;
21
22         int substr_len=0, str_len=1;
23         while( *dir_name ){
24                 if(*dir_name=='/'){
25                         if( substr_len ){
26                                 // If there was a non-zero length string between two '/'s, then record it
27                                 list_tail->str_len=substr_len;
28                                 str_len+=substr_len+1;
29                                
30                                 temp=malloc(sizeof(list));
31                                 list_tail->next=temp;
32                                 temp->prev=list_tail;
33                                 list_tail=temp;
34                                 list_tail->next=NULL;
35                         }
36                         list_tail->dir_name=dir_name+1;
37                         ++dir_name;
38                         substr_len=0;
39
40                         if(*(dir_name)=='.'){
41                                 if(*(dir_name+1)=='/'){ // case: "/./"
42                                         // Clear tail node
43                                         ++dir_name;
44                                         list_tail->dir_name=dir_name+1;
45                                         substr_len=0;
46                                 }
47                                 if(*(dir_name+1)=='.'){
48                                         if(*(dir_name+2)=='/'){ //case: "/../"
49                                                 // Pop the tail node off the list
50                                                 temp=list_tail;
51                                                 list_tail=list_tail->prev;
52                                                 list_tail->next=NULL;
53                                                 free(temp);
54                                        
55                                                 // Clear tail node
56                                                 dir_name+=2;
57                                                 str_len-=list_tail->str_len+1;
58                                                 list_tail->dir_name=dir_name+1;
59                                                 substr_len=0;
60
61                                         }
62                                 }
63                         }
64                         continue;
65                 }
66                 ++dir_name;
67                 ++substr_len;
68         }
69
70         if(substr_len){
71                 // If there is something still at the end, add it
72                 list_tail->str_len=substr_len;
73                 str_len+=substr_len+1;
74         }else{
75                 // Pop the tail node off the list
76                 temp=list_tail;
77                 list_tail=list_tail->prev;
78                 list_tail->next=NULL;
79                 free(temp);
80         }
81        
82         char *new_str=malloc(str_len+1);
83         new_str[0]='/';
84         int str_pos=1;
85         while( list_head ){
86                 // Reconstruct the string
87                 memcpy(new_str+str_pos,list_head->dir_name, list_head->str_len);
88                 str_pos+=list_head->str_len;
89                 new_str[str_pos++]='/';
90                 int i;
91
92                 // Pop the head node off the list
93                 temp=list_head;
94                 list_head=list_head->next;
95                 free(temp);
96         }
97         new_str[str_pos]='\0';
98         return new_str;
99 }
100
101 int db_split_file_name( char *file_path, char **dir_name, char **file_name ){
102         // Find the last '/'
103         char *tmp_file_name, *i=file_path;
104         while( *i++ )
105                 if( *i =='/' )
106                         tmp_file_name=i+1;
107         // Copy the file_name
108         *file_name = malloc(i-tmp_file_name+1);
109         memcpy(*file_name, tmp_file_name,i-tmp_file_name);
110         (*file_name)[i-tmp_file_name]='\0';
111
112         // Copy and normalize the directory name
113         char *tmp_dir_name=malloc(tmp_file_name-file_path+1);
114         memcpy(tmp_dir_name, file_path, tmp_file_name-file_path);
115         tmp_dir_name[tmp_file_name-file_path]='\0';
116        
117         *dir_name=db_normalize_dir_name(tmp_dir_name);
118         free(tmp_dir_name);
119        
120         return 0;
121 }
122
123 int db_parse_file_res( PGresult *res, file_t *file ){
124         // Initialize format
125         if( !NUM_FILE_FIELDS ){
126                 NUM_FILE_FIELDS = sizeof(file_format)/4+1;
127
128                 if( PQnfields(res) != NUM_FILE_FIELDS ){
129                         NUM_FILE_FIELDS = 0;
130                         return NULL;
131                 }
132
133         // Fill file_format with column numbers
134 #define db_int(name)    file_format.name = PQfnumber(res, #name );
135 #define db_long(name)   file_format.name = PQfnumber(res, #name );
136 #define db_string(name) file_format.name = PQfnumber(res, #name );
137 #include "file.db"
138         }
139
140         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
141        
142         if( PQnfields(res) != NUM_FILE_FIELDS ) return NULL;
143
144         // Fill stat
145 #define db_int(name)    file->name = atoi(PQgetvalue(res, 0, file_format.name ));
146 #define db_long(name)   file->name = atol(PQgetvalue(res, 0, file_format.name ));
147 #define db_string(name) file->name = strdup(PQgetvalue(res, 0, file_format.name ));
148 #include "file.db"
149         
150         return 0;
151 }
152
153 int db_parse_dir_res( PGresult *res, dir_t *dir ){
154         // Initialize format
155         if( !NUM_DIR_FIELDS ){
156                 NUM_DIR_FIELDS = sizeof(dir_format)/4;
157
158                 if( PQnfields(res) != NUM_DIR_FIELDS ){
159                         NUM_DIR_FIELDS = 0;
160                         return NULL;
161                 }
162
163         // Fill dir_format with column numbers
164 #define db_int(name)    dir_format.name = PQfnumber(res, #name );
165 #define db_long(name)   dir_format.name = PQfnumber(res, #name );
166 #define db_string(name) dir_format.name = PQfnumber(res, #name );
167 #include "dir.db"
168         }
169
170         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
171        
172         if( PQnfields(res) != NUM_DIR_FIELDS ) return NULL;
173
174         // Fill stat
175 #define db_int(name)    dir->name = atoi(PQgetvalue(res, 0, dir_format.name ));
176 #define db_long(name)   dir->name = atol(PQgetvalue(res, 0, dir_format.name ));
177 #define db_string(name) dir->name = strdup(PQgetvalue(res, 0, dir_format.name ));
178 #include "dir.db"
179         
180         return 0;
181 }
182
183 int db_get_file_max_revision( int file_id ){
184         // Make the request
185         char pq_request[BUFFER_SIZE];
186         sprintf(pq_request,"SELECT MAX(revision_id) "
187                            "FROM file "
188                            "WHERE file_id = \'%i\'",
189                            file_id);
190         db_debug_rq(db_get_file_max_revision);
191         PGresult *res=PQexec(pq_conn,pq_request);
192
193         // Check to see that the something was returned
194         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
195        
196         if( !PQntuples(res) ) return NULL;
197
198         // The result should be in the first row of the first column
199         int revision_id=atoi(PQgetvalue(res,0,0));
200
201         PQclear(res);
202
203         return revision_id;
204 }
205
206
207
208 int db_get_file_id( char *file_path ){
209         char *file_name, *dir_name;
210         db_split_file_name(file_path, &dir_name, &file_name);
211
212         // Make the request
213         char pq_request[BUFFER_SIZE];
214         sprintf(pq_request,"SELECT file_id "
215                            "FROM file WHERE file_name = \'%s\' "
216                            "AND directory_path = \'%s\'",
217                            file_name,dir_name);
218         db_debug_rq(db_get_file_id);
219         PGresult *res=PQexec(pq_conn,pq_request);
220
221         // Check for returned data
222         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
223
224         if( !PQntuples(res) ) return NULL;
225
226         // The result should be in the first row of the first column
227         int file_id=atoi(PQgetvalue(res,0,0));
228        
229         free(dir_name);
230         free(file_name);
231         PQclear(res);
232
233         return file_id;
234 }
235
236
237 file_t *db_get_file( int file_id ){
238         file_t *stat=malloc(sizeof(file_t));
239
240         // Make PQ request
241         char pq_request[BUFFER_SIZE];
242         sprintf(pq_request,"SELECT "
243 #define db_int(name)    #name ", "
244 #define db_long(name)   #name ", "
245 #define db_string(name) #name ", "
246 #include "file.db"
247                            "file_uid "
248                            "FROM file "
249                            "WHERE file_id = \'%i\' "
250                            "AND revision_id = (SELECT MAX(revision_id) FROM file WHERE file_Id = \'%i\')",
251                            file_id, file_id);
252         db_debug_rq(db_get_file);
253         PGresult *res=PQexec(pq_conn,pq_request);
254
255         db_parse_file_res(res, stat);
256
257         PQclear(res);
258
259         return stat;
260 }
261
262
263 file_t *db_get_file_rev( int file_id, int revision_id ){
264         file_t *stat=malloc(sizeof(file_t));
265
266         // Make PQ request
267         char pq_request[BUFFER_SIZE];
268         sprintf(pq_request,"SELECT "
269 #define db_int(name)    #name ", "
270 #define db_long(name)   #name ", "
271 #define db_string(name) #name ", "
272 #include "file.db"
273                            "file_uid "
274                            "FROM file "
275                            "WHERE file_id = \'%i\' "
276                            "AND revision_id = \'%i\'",
277                            file_id, revision_id);
278         PGresult *res=PQexec(pq_conn,pq_request);
279
280         db_parse_file_res(res, stat);
281        
282         PQclear(res);
283
284         return stat;
285 }
286
287 char *db_get_file_data( int file_id ){
288         char pq_request[BUFFER_SIZE];
289         sprintf(pq_request,"SELECT data "
290                            "FROM file "
291                            "WHERE file_id = \'%i\' "
292                            "AND revision_id = (SELECT MAX(revision_id) FROM file WHERE file_id = \'%i\')",
293                            file_id, file_id);
294         db_debug_rq(db_get_file_data);
295         PGresult *res=PQexec(pq_conn,pq_request);
296
297         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
298
299         int data_len=PQgetlength(res,0,0);
300         char *data=malloc(data_len);
301         memcpy(data,PQgetvalue(res,0,0),data_len);
302         int udata_len;
303         char *udata=PQunescapeBytea(data,&udata_len);
304
305         free(data);
306         PQclear(res);
307
308         return udata;
309 }
310
311
312 char *db_get_file_rev_data( int file_id, int revision_id ){
313         int i = db_get_file_max_revision(file_id);
314         char *data, *diff, *temp;
315        
316         char pq_request[BUFFER_SIZE];
317         sprintf(pq_request,"SELECT data "
318                            "FROM file "
319                            "WHERE file_id = \'%i\' "
320                            "AND revision_id = \'%i\'",
321                            file_id,i);
322         PGresult *res=PQexec(pq_conn,pq_request);
323
324         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
325
326         int data_len=PQgetlength(res,0,0), diff_len, temp_len;
327         data=malloc(data_len);
328         memcpy(data,PQgetvalue(res,0,0),data_len);
329         int udata_len;
330         char *udata=PQunescapeBytea(data,&udata_len);
331         free(data);
332
333         PQclear(res);
334
335         while( --i >= revision_id ){
336                 char pq_request[BUFFER_SIZE];
337                 sprintf(pq_request,"SELECT data "
338                                    "FROM file "
339                                    "WHERE file_id = \'%i\' "
340                                    "AND revision_id = \'%i\'",
341                                    file_id,i);
342                 db_debug_rq(db_get_file_rev_udata);
343                 PGresult *res=PQexec(pq_conn,pq_request);
344
345                 if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
346
347                 diff_len=PQgetlength(res,0,0);
348                 diff=malloc(diff_len);
349                 memcpy(diff,PQgetvalue(res,0,0),diff_len);
350
351                 int udiff_len;
352                 char *udiff = PQunescapeBytea(diff,&udiff_len);
353
354                 temp=malloc(XD3_ALLOCSIZE);
355
356                 xd3_decode_memory(udiff, udiff_len,
357                                   udata, udata_len,
358                                   temp, &temp_len, XD3_ALLOCSIZE,
359                                   0);
360                
361                 free(diff);
362                 PQfreemem(udata);
363                 PQfreemem(udiff);
364                 PQclear(res);
365                 udata = temp;
366                 udata_len = temp_len;
367         }
368
369         return udata;
370 }
371
372
373 int db_get_dir_id( char *dir_path ){
374         char *dir_name=db_normalize_dir_name(dir_path);
375
376         // Make the request
377         char pq_request[BUFFER_SIZE];
378         sprintf(pq_request,"SELECT directory_id "
379                            "FROM directory "
380                            "WHERE directory_path = \'%s\'",
381                            dir_name);
382         PGresult *res=PQexec(pq_conn,pq_request);
383
384         // Check to see that the file exists
385         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
386        
387         if( !PQntuples(res) ) return NULL;
388
389         // The result should be in the first row of the first column
390         int dir_id=atoi(PQgetvalue(res,0,0));
391
392         // Clean up and return
393         free(dir_name);
394         PQclear(res);
395
396         return dir_id;
397 }
398
399
400 dir_t *db_get_dir( int dir_id ){
401         dir_t *stat=malloc(sizeof(dir_t));
402
403         char pq_request[BUFFER_SIZE];
404         sprintf(pq_request,"SELECT * "
405                            "FROM directory "
406                            "WHERE directory_id = \'%i\' "
407                            "AND revision_id = (SELECT MAX(revision_id) FROM directory WHERE directory_id = \'%i\')",
408                            dir_id, dir_id);
409         PGresult *res=PQexec(pq_conn,pq_request);
410
411         db_parse_dir_res(res,stat);
412
413         PQclear(res);
414
415         return stat;
416 }
417
418
419 dir_t *db_get_dir_rev( int dir_id, int revision_id ){
420         dir_t *stat=malloc(sizeof(dir_t));
421
422         char pq_request[BUFFER_SIZE];
423         sprintf(pq_request,"SELECT * "
424                            "FROM directory "
425                            "WHERE directory_id = \'%i\' "
426                            "AND revision_id = \'%i\'",
427                            dir_id, revision_id);
428         PGresult *res=PQexec(pq_conn,pq_request);
429
430         db_parse_dir_res( res, stat );
431
432         PQclear(res);
433
434         return stat;
435 }
436
437 int db_get_dir_max_revision( int dir_id ){
438         // Make the request
439         char pq_request[BUFFER_SIZE];
440         sprintf(pq_request,"SELECT MAX(revision_id) "
441                            "FROM directory "
442                            "WHERE directory_id = \'%i\'",
443                            dir_id);
444         PGresult *res=PQexec(pq_conn,pq_request);
445
446         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
447
448         // The result should be in the first row of the first column
449         int revision_id=atoi(PQgetvalue(res,0,0));
450
451         PQclear(res);
452
453         return revision_id;
454 }
455
456
457 int db_init(char *host, int port, char *dbname, char *username, char *password){
458         char pq_request[BUFFER_SIZE];
459         sprintf(pq_request,"host=%s port=%i dbname=%s user=%s password=%s", host, port, dbname, username, password);
460         pq_conn=PQconnectdb(pq_request);
461        
462         NUM_FILE_FIELDS = 0;
463         NUM_DIR_FIELDS = 0;
464         NUM_STREAM_FIELDS = 0;
465
466         if( PQstatus( pq_conn ) != CONNECTION_OK )
467                 return -1;
468         else
469                 return 0;
470 }
471
472
473 int db_destroy(){
474         PQfinish(pq_conn);
475         return 0;
476 }
477
478
479 stream_t *db_get_stream( int stream_id ){
480         stream_t *stat=malloc(sizeof(stream_t));
481
482         char pq_request[BUFFER_SIZE];
483         sprintf(pq_request,"SELECT * "
484                            "FROM stream "
485                            "WHERE stream_id = \'%i\'",
486                            stream_id);
487         PGresult *res=PQexec(pq_conn,pq_request);
488
489         if( !NUM_STREAM_FIELDS ){
490                 NUM_STREAM_FIELDS = sizeof(stream_format)/4;
491
492                 if( PQnfields(res) != NUM_STREAM_FIELDS ){
493                         NUM_STREAM_FIELDS = 0;
494                         return NULL;
495                 }
496
497         // Fill stream_format with column numbers
498 #define db_int(name)    stream_format.name = PQfnumber(res, #name );
499 #define db_long(name)   stream_format.name = PQfnumber(res, #name );
500 #define db_string(name) stream_format.name = PQfnumber(res, #name );
501 #include "stream.db"
502         }
503
504         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
505        
506         if( PQnfields(res) != NUM_STREAM_FIELDS ) return NULL;
507
508         // Fill stat
509 #define db_int(name)    stat->name = atoi(PQgetvalue(res, 0, stream_format.name ));
510 #define db_long(name)   stat->name = atol(PQgetvalue(res, 0, stream_format.name ));
511 #define db_string(name) stat->name = strdup(PQgetvalue(res, 0, stream_format.name ));
512 #include "stream.db"
513         
514         PQclear(res);
515
516         return stat;
517 }
518
519 int db_get_stream_max_id(){
520         PGresult *res=PQexec(pq_conn,"SELECT MAX(stream_id) FROM stream");
521
522         if( PQresultStatus(res) != PGRES_TUPLES_OK ) return NULL;
523
524         int stream_id=atoi(PQgetvalue(res,0,0));
525
526         PQclear(res);
527
528         return stream_id;
529 }
530
5