1 | /* |
---|
2 | * |
---|
3 | * Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology |
---|
4 | * Developed by the MIT Student Information Processing Board (SIPB). |
---|
5 | * For copying information, see the file mit-copyright.h in this release. |
---|
6 | * |
---|
7 | */ |
---|
8 | /* |
---|
9 | * $Id: dsname.c,v 1.29 2006-03-10 07:11:38 ghudson Exp $ |
---|
10 | * |
---|
11 | */ |
---|
12 | |
---|
13 | /* |
---|
14 | * db: Implements user's meetings database. |
---|
15 | * |
---|
16 | */ |
---|
17 | |
---|
18 | #include <stdio.h> |
---|
19 | #include <stdlib.h> |
---|
20 | #include <string.h> |
---|
21 | #if HAVE_UNISTD_H |
---|
22 | #include <unistd.h> |
---|
23 | #endif |
---|
24 | #include <pwd.h> |
---|
25 | #include <sys/file.h> |
---|
26 | #include <sys/param.h> |
---|
27 | #include <errno.h> |
---|
28 | #include <assert.h> |
---|
29 | #include <discuss/dsname.h> |
---|
30 | #include <discuss/dsc_et.h> |
---|
31 | #include "ansi.h" |
---|
32 | |
---|
33 | #ifndef lint |
---|
34 | static const char rcsid_dsname_c[] = |
---|
35 | "$Id: dsname.c,v 1.29 2006-03-10 07:11:38 ghudson Exp $"; |
---|
36 | #endif |
---|
37 | |
---|
38 | extern char *local_realm (); |
---|
39 | |
---|
40 | /* |
---|
41 | * Format of data file: |
---|
42 | * status:last_time:last_seen:uid:name1,name2name3,....,nameN: |
---|
43 | */ |
---|
44 | |
---|
45 | static FILE *db = (FILE *)NULL; |
---|
46 | static char *db_file = (char *)NULL; |
---|
47 | static char *db_user_id = (char *)NULL; |
---|
48 | |
---|
49 | static server_name_blk current = { |
---|
50 | (char *)NULL, (char *)NULL, (char *)NULL, 0, 0, 0 |
---|
51 | }; |
---|
52 | |
---|
53 | static char disrcbuf[MAXPATHLEN]; /* user's MEETINGS file */ |
---|
54 | static char *disrcfile = NULL; /* pointer to above */ |
---|
55 | |
---|
56 | static char mtgs[] = "/.meetings"; |
---|
57 | |
---|
58 | |
---|
59 | #ifdef __GNUC__ |
---|
60 | #define INLINE inline |
---|
61 | #else |
---|
62 | #define INLINE |
---|
63 | #endif |
---|
64 | |
---|
65 | /* |
---|
66 | * ds() -- duplicate a string. a useful utility routine... |
---|
67 | */ |
---|
68 | |
---|
69 | INLINE static char * ds(s) |
---|
70 | const char *s; |
---|
71 | { |
---|
72 | register int len = strlen (s) + 1; |
---|
73 | register char *ns = malloc (len); |
---|
74 | memcpy (ns, s, len); |
---|
75 | return (ns); |
---|
76 | } |
---|
77 | |
---|
78 | /* |
---|
79 | * Attempt to locate user's .meetings file. This is intended to be |
---|
80 | * used as a test routine from an application. |
---|
81 | * |
---|
82 | * search path is: |
---|
83 | * $MEETINGS environment variable |
---|
84 | * $HOME/.meetings |
---|
85 | * <pw->pw_dir>/.meetings |
---|
86 | * This function is "sticky"; it only evaluates the filename once. |
---|
87 | */ |
---|
88 | |
---|
89 | int find_rc_filename() |
---|
90 | { |
---|
91 | struct passwd *pw = NULL; |
---|
92 | register char *cp; |
---|
93 | |
---|
94 | if (disrcfile) |
---|
95 | return 0; |
---|
96 | |
---|
97 | pw = getpwuid(getuid()); |
---|
98 | if (!pw) |
---|
99 | return NO_SUCH_USER; |
---|
100 | |
---|
101 | cp = getenv("MEETINGS"); |
---|
102 | if (cp) |
---|
103 | strcpy(disrcbuf, cp); |
---|
104 | if (!cp) { |
---|
105 | cp = getenv("HOME"); |
---|
106 | if (cp) { |
---|
107 | strcpy(disrcbuf, cp); |
---|
108 | strcat(disrcbuf, mtgs); |
---|
109 | } |
---|
110 | } |
---|
111 | if (!cp) { |
---|
112 | strcpy(disrcbuf, pw->pw_dir); |
---|
113 | strcat(disrcbuf, mtgs); |
---|
114 | } |
---|
115 | if (!access(disrcbuf, R_OK|W_OK)) { |
---|
116 | disrcfile = disrcbuf; |
---|
117 | return 0; |
---|
118 | } |
---|
119 | return errno; |
---|
120 | } |
---|
121 | |
---|
122 | static void clear_current () { |
---|
123 | if (current.hostname) { |
---|
124 | free (current.hostname); |
---|
125 | current.hostname = (char *) NULL; |
---|
126 | } |
---|
127 | if (current.pathname) { |
---|
128 | free (current.pathname); |
---|
129 | current.pathname = (char *) NULL; |
---|
130 | } |
---|
131 | if (current.alias_list) { |
---|
132 | free (current.alias_list); |
---|
133 | current.alias_list = (char *) NULL; |
---|
134 | } |
---|
135 | if (current.spare) { |
---|
136 | free (current.spare); |
---|
137 | current.spare = (char *) NULL; |
---|
138 | } |
---|
139 | } |
---|
140 | |
---|
141 | static void enddbent() |
---|
142 | { |
---|
143 | if (db) { |
---|
144 | fclose(db); |
---|
145 | db = (FILE *)NULL; |
---|
146 | free(db_file); |
---|
147 | db_file = (char *)NULL; |
---|
148 | free(db_user_id); |
---|
149 | db_user_id = (char *)NULL; |
---|
150 | } |
---|
151 | clear_current (); |
---|
152 | } |
---|
153 | |
---|
154 | /* |
---|
155 | * getdbent() -- get the next entry out of the file. returns |
---|
156 | * zero on end of file or uncorrectable error, one on success, minus |
---|
157 | * one on correctable error. |
---|
158 | */ |
---|
159 | |
---|
160 | static int getdbent() |
---|
161 | { |
---|
162 | char buffer[BUFSIZ]; |
---|
163 | char *bufp, *cp; |
---|
164 | |
---|
165 | if (!db) { |
---|
166 | errno = NO_MTGS_FILE; |
---|
167 | return(0); |
---|
168 | } |
---|
169 | if (!fgets(buffer, BUFSIZ, db)) { |
---|
170 | return 0; |
---|
171 | } |
---|
172 | |
---|
173 | bufp = strchr(buffer, '\n'); |
---|
174 | if (bufp) |
---|
175 | *bufp = '\0'; |
---|
176 | bufp = buffer; |
---|
177 | |
---|
178 | /* meeting status flags (per-user) */ |
---|
179 | current.status = atoi(bufp); |
---|
180 | bufp = strchr(bufp, ':'); |
---|
181 | if (!bufp) { |
---|
182 | bad_fmt: |
---|
183 | errno = BAD_MTGS_FILE; |
---|
184 | return(-1); |
---|
185 | } |
---|
186 | else |
---|
187 | bufp++; |
---|
188 | |
---|
189 | /* date user last attended meeting */ |
---|
190 | current.date_attended = atoi(bufp); |
---|
191 | bufp = strchr(bufp, ':'); |
---|
192 | if (!bufp) |
---|
193 | goto bad_fmt; |
---|
194 | else |
---|
195 | bufp++; |
---|
196 | |
---|
197 | /* last transaction seen */ |
---|
198 | current.last = atoi(bufp); |
---|
199 | bufp = strchr(bufp, ':'); |
---|
200 | if (!bufp) |
---|
201 | goto bad_fmt; |
---|
202 | else |
---|
203 | bufp++; |
---|
204 | |
---|
205 | /* hostname of meeting */ |
---|
206 | if (current.hostname) |
---|
207 | free(current.hostname); |
---|
208 | cp = strchr(bufp, ':'); |
---|
209 | if (cp == NULL) goto bad_fmt; |
---|
210 | else { |
---|
211 | *cp = '\0'; |
---|
212 | current.hostname = ds(bufp); |
---|
213 | bufp = cp+1; |
---|
214 | } |
---|
215 | |
---|
216 | /* pathname of meeting on remote host */ |
---|
217 | if (current.pathname) |
---|
218 | free(current.pathname); |
---|
219 | cp = strchr(bufp, ':'); |
---|
220 | if (cp == NULL) goto bad_fmt; |
---|
221 | else { |
---|
222 | *cp = '\0'; |
---|
223 | current.pathname = ds(bufp); |
---|
224 | bufp = cp+1; |
---|
225 | } |
---|
226 | |
---|
227 | /* list of aliases for meeting */ |
---|
228 | if (current.alias_list) |
---|
229 | free(current.alias_list); |
---|
230 | cp = strchr(bufp, ':'); |
---|
231 | if (cp == NULL) goto bad_fmt; |
---|
232 | else { |
---|
233 | *cp = '\0'; |
---|
234 | current.alias_list = ds(bufp); |
---|
235 | bufp = cp+1; |
---|
236 | } |
---|
237 | |
---|
238 | if (current.spare) |
---|
239 | free(current.spare); |
---|
240 | current.spare = ds(bufp); |
---|
241 | |
---|
242 | return(1); |
---|
243 | } |
---|
244 | |
---|
245 | static int setdbent(user_id) |
---|
246 | const char *user_id; |
---|
247 | { |
---|
248 | char *auid; |
---|
249 | register int code; |
---|
250 | |
---|
251 | enddbent(); |
---|
252 | |
---|
253 | if (!user_id) |
---|
254 | user_id = ""; |
---|
255 | if (!disrcfile) { |
---|
256 | code = find_rc_filename(); |
---|
257 | if (code) |
---|
258 | return code; |
---|
259 | } |
---|
260 | db_file = ds(disrcfile); |
---|
261 | |
---|
262 | db = fopen(db_file, "r"); |
---|
263 | if (!db) |
---|
264 | return(errno); |
---|
265 | if (db_user_id) |
---|
266 | free(db_user_id); |
---|
267 | db_user_id = ds(user_id); |
---|
268 | if (current.user_id) |
---|
269 | free(current.user_id); |
---|
270 | current.user_id = ds(user_id); |
---|
271 | return(0); |
---|
272 | } |
---|
273 | |
---|
274 | static int is_a_name(name) |
---|
275 | register char *name; |
---|
276 | { |
---|
277 | register int len; |
---|
278 | register char *ns = current.alias_list; |
---|
279 | |
---|
280 | if (*name == '*') |
---|
281 | return(1); |
---|
282 | len = strlen(name); |
---|
283 | |
---|
284 | while (1) { |
---|
285 | if (!strncmp(name, ns, len) && (!ns[len] || ns[len] == ',')) { |
---|
286 | return(1); |
---|
287 | } |
---|
288 | ns = strchr(ns+1, ','); |
---|
289 | if (!ns || !ns[1]) { |
---|
290 | return(0); |
---|
291 | } |
---|
292 | ns++; |
---|
293 | } |
---|
294 | } |
---|
295 | |
---|
296 | static char ** expand(list) |
---|
297 | char *list; |
---|
298 | { |
---|
299 | register int num = 2; |
---|
300 | register char *cp; |
---|
301 | register char **rv, **rv1; |
---|
302 | for (cp = list; cp;) { |
---|
303 | num++; |
---|
304 | cp = strchr(cp, ','); |
---|
305 | if (cp) |
---|
306 | cp++; |
---|
307 | } |
---|
308 | rv = (char **) calloc (num, sizeof(char *)); |
---|
309 | rv1 = rv; |
---|
310 | while (list && *list) { |
---|
311 | while (*list == ',') |
---|
312 | list++; |
---|
313 | cp = strchr(list, ','); |
---|
314 | if (cp) |
---|
315 | *cp = '\0'; |
---|
316 | *rv1 = ds(list); |
---|
317 | rv1++; |
---|
318 | if (cp) { |
---|
319 | *cp = ','; |
---|
320 | cp++; |
---|
321 | list = cp; |
---|
322 | } |
---|
323 | else list = (char *) NULL; |
---|
324 | } |
---|
325 | *rv1 = (char *) NULL; |
---|
326 | return(rv); |
---|
327 | } |
---|
328 | |
---|
329 | static char * compress(list) |
---|
330 | char **list; |
---|
331 | { |
---|
332 | int len; |
---|
333 | char **cp; |
---|
334 | char *rv; |
---|
335 | len = 1; |
---|
336 | for (cp = list; *cp; cp++) |
---|
337 | len += 1 + strlen(*cp); |
---|
338 | rv = malloc (len); |
---|
339 | strcpy(rv, *list); |
---|
340 | for (cp = list+1; *cp; cp++) { |
---|
341 | strcat(rv, ","); |
---|
342 | strcat(rv, *cp); |
---|
343 | } |
---|
344 | return (rv); |
---|
345 | } |
---|
346 | |
---|
347 | dsc_expand_mtg_set(user_id, name, set, num, result) |
---|
348 | char *user_id; /* userid to do lookup for */ |
---|
349 | char *name; /* user's name for meeting */ |
---|
350 | name_blk **set; /* returned values */ |
---|
351 | int *num; /* number of returned meetings */ |
---|
352 | int *result; /* return code */ |
---|
353 | { |
---|
354 | int count; |
---|
355 | register int r; |
---|
356 | |
---|
357 | *set = 0; |
---|
358 | *num = 0; |
---|
359 | *result = 0; |
---|
360 | |
---|
361 | if (!user_id) |
---|
362 | user_id = ""; |
---|
363 | if (!name) { |
---|
364 | *result = EINVAL; |
---|
365 | *num = 0; |
---|
366 | return; |
---|
367 | } |
---|
368 | r = setdbent(user_id); |
---|
369 | if (r) { |
---|
370 | *result = r; |
---|
371 | return; |
---|
372 | } |
---|
373 | count = 0; |
---|
374 | while ((r=getdbent()) > 0) { |
---|
375 | if (is_a_name(name)) |
---|
376 | count++; |
---|
377 | } |
---|
378 | if (r) { /* getdbent returns -1 */ |
---|
379 | *result = errno; |
---|
380 | return; |
---|
381 | } |
---|
382 | r = setdbent(user_id); |
---|
383 | if (r) { |
---|
384 | *result = r; |
---|
385 | return; |
---|
386 | } |
---|
387 | *set = (name_blk *) malloc(count * sizeof(name_blk)); |
---|
388 | if (*set == (name_blk *)NULL) { |
---|
389 | *result = errno; |
---|
390 | return; |
---|
391 | } |
---|
392 | while ((r=getdbent()) > 0) |
---|
393 | if (is_a_name(name)) { |
---|
394 | register name_blk *nb = *set + (*num)++; |
---|
395 | memset((char *)nb, 0, sizeof(*nb)); |
---|
396 | nb->date_attended = current.date_attended; |
---|
397 | nb->last = current.last; |
---|
398 | nb->status = current.status; |
---|
399 | nb->hostname = ds(current.hostname); |
---|
400 | nb->pathname = ds(current.pathname); |
---|
401 | nb->aliases = expand(current.alias_list); |
---|
402 | nb->spare = ds(current.spare); |
---|
403 | nb->user_id = ds(user_id); |
---|
404 | } |
---|
405 | if (r) |
---|
406 | *result = r; |
---|
407 | } |
---|
408 | |
---|
409 | void dsc_copy_name_blk (src, dest) |
---|
410 | register name_blk *src, *dest; |
---|
411 | { |
---|
412 | char **cpp; |
---|
413 | char **dpp; |
---|
414 | int count; |
---|
415 | |
---|
416 | *dest = *src; |
---|
417 | dest->hostname = ds(dest->hostname); |
---|
418 | dest->pathname = ds(dest->pathname); |
---|
419 | dest->user_id = ds(dest->user_id); |
---|
420 | dest->spare = ds(dest->spare); |
---|
421 | |
---|
422 | for (count=1, cpp = src->aliases; *cpp; cpp++) { |
---|
423 | count++; |
---|
424 | } |
---|
425 | dpp = dest->aliases = (char **)malloc ((count+1) * sizeof (char *)); |
---|
426 | for (cpp = src->aliases; *cpp; cpp++, dpp++) |
---|
427 | *dpp = ds (*cpp); |
---|
428 | *dpp = NULL; |
---|
429 | } |
---|
430 | /* |
---|
431 | * Free all allocated storage associated with *nbp; |
---|
432 | * Note: this does not free the nbp itself. |
---|
433 | */ |
---|
434 | void dsc_destroy_name_blk(nbp) |
---|
435 | name_blk *nbp; |
---|
436 | { |
---|
437 | if (nbp->aliases) { |
---|
438 | register char **alp = nbp->aliases; |
---|
439 | while (*alp) { |
---|
440 | free (*alp); |
---|
441 | alp++; |
---|
442 | } |
---|
443 | free (nbp->aliases); |
---|
444 | nbp->aliases = 0; |
---|
445 | } |
---|
446 | if (nbp->hostname) { |
---|
447 | free(nbp->hostname); |
---|
448 | nbp->hostname = 0; |
---|
449 | } |
---|
450 | if (nbp->pathname) { |
---|
451 | free(nbp->pathname); |
---|
452 | nbp->pathname = 0; |
---|
453 | } |
---|
454 | if (nbp->spare) { |
---|
455 | free(nbp->spare); |
---|
456 | nbp->spare = 0; |
---|
457 | } |
---|
458 | if (nbp->user_id) { |
---|
459 | free (nbp->user_id); |
---|
460 | nbp->user_id = 0; |
---|
461 | } |
---|
462 | } |
---|
463 | |
---|
464 | void dsc_destroy_mtg_set(nbp, count) |
---|
465 | register name_blk *nbp; |
---|
466 | register int count; |
---|
467 | { |
---|
468 | register int i; |
---|
469 | |
---|
470 | if (nbp == NULL) return; |
---|
471 | for (i=0; i<count; i++) |
---|
472 | dsc_destroy_name_blk(&nbp[i]); |
---|
473 | |
---|
474 | free((char *)nbp); |
---|
475 | } |
---|
476 | |
---|
477 | dsc_get_mtg (user_id, name, nbp, result) |
---|
478 | char *user_id; |
---|
479 | char *name; |
---|
480 | name_blk *nbp; |
---|
481 | int *result; |
---|
482 | { |
---|
483 | name_blk *set = NULL; |
---|
484 | int num; |
---|
485 | |
---|
486 | if (!name) { |
---|
487 | *result = EINVAL; |
---|
488 | } |
---|
489 | dsc_expand_mtg_set(user_id, name, &set, &num, result); |
---|
490 | if (num == 0) { |
---|
491 | if (!*result) |
---|
492 | *result = NO_SUCH_MTG; |
---|
493 | goto bad; |
---|
494 | } else if (num > 1) { |
---|
495 | register int i; |
---|
496 | for (i = 1; i < num; i++) { |
---|
497 | dsc_destroy_name_blk(&set[i]); |
---|
498 | } |
---|
499 | } |
---|
500 | memcpy(nbp, &set[0], sizeof(name_blk)); |
---|
501 | |
---|
502 | bad: |
---|
503 | if (set) |
---|
504 | free((char *)set); |
---|
505 | } |
---|
506 | |
---|
507 | static const char format[] = "%d:%d:%d:%s:%s:%s:%s\n"; |
---|
508 | |
---|
509 | void dsc_update_mtg_set(user_id, set, num, result) |
---|
510 | char const *user_id; /* input */ |
---|
511 | name_blk *set; /* array of name_blk's */ |
---|
512 | int num; /* number in set */ |
---|
513 | int *result; /* error code */ |
---|
514 | { |
---|
515 | name_blk *nbp; |
---|
516 | int i; |
---|
517 | register int r; |
---|
518 | char *touched; /* array of booleans */ |
---|
519 | char *new_name; |
---|
520 | FILE *new_file = NULL; |
---|
521 | char *old_name; |
---|
522 | |
---|
523 | if (!num) { |
---|
524 | *result = 0; |
---|
525 | return; |
---|
526 | } |
---|
527 | else if (!set) { |
---|
528 | *result = EINVAL; |
---|
529 | return; |
---|
530 | } |
---|
531 | if (*result = setdbent(user_id)) { |
---|
532 | if (*result != NO_MTGS_FILE && *result != ENOENT) |
---|
533 | return; |
---|
534 | else |
---|
535 | *result = 0; |
---|
536 | } |
---|
537 | |
---|
538 | new_name = malloc(strlen(db_file) + 2); |
---|
539 | strcpy (new_name, db_file); |
---|
540 | strcat (new_name, "~"); /* emacsish, but who cares? */ |
---|
541 | old_name = malloc(strlen(db_file) + 1); |
---|
542 | strcpy (old_name, db_file); |
---|
543 | |
---|
544 | new_file = fopen (new_name, "w+"); |
---|
545 | if (new_file == NULL) { |
---|
546 | *result = errno; |
---|
547 | free(old_name); |
---|
548 | free (new_name); |
---|
549 | return; |
---|
550 | } |
---|
551 | |
---|
552 | touched = malloc (num); |
---|
553 | for (i = 0; i < num; i++) |
---|
554 | touched[i] = 0; |
---|
555 | |
---|
556 | while ((r=getdbent()) != 0) { |
---|
557 | if (r == -1) { /* if bad format, we complain loudly */ |
---|
558 | *result = BAD_MTGS_FILE; |
---|
559 | goto punt; |
---|
560 | } |
---|
561 | /* walk through user structures, look for matching entries */ |
---|
562 | for (i = 0, nbp = set; i < num; i++, nbp++) { |
---|
563 | if (!strcmp (current.hostname, nbp -> hostname) && |
---|
564 | !strcmp(current.pathname, nbp->pathname)) { |
---|
565 | /* match, update */ |
---|
566 | current.last = nbp -> last; |
---|
567 | current.date_attended = |
---|
568 | nbp -> date_attended; |
---|
569 | current.status = nbp -> status; |
---|
570 | if (current.alias_list != NULL) |
---|
571 | free (current.alias_list); |
---|
572 | current.alias_list = compress(nbp -> aliases); |
---|
573 | if (current.spare) |
---|
574 | free (current.spare); |
---|
575 | current.spare = ds(nbp->spare); |
---|
576 | touched[i] = 1; |
---|
577 | } |
---|
578 | } |
---|
579 | if (current.status & DSC_ST_DELETED) continue; |
---|
580 | |
---|
581 | if (fprintf(new_file, format, |
---|
582 | current.status, current.date_attended, current.last, |
---|
583 | current.hostname, current.pathname, |
---|
584 | current.alias_list, current.spare) == EOF) |
---|
585 | goto punt; |
---|
586 | } |
---|
587 | |
---|
588 | clear_current (); |
---|
589 | |
---|
590 | /* clean up ones we haven't touched in memory yet */ |
---|
591 | for (i = 0, nbp = set; i < num; i++, nbp++) { |
---|
592 | if (!touched[i]) { |
---|
593 | char *temp = compress (nbp->aliases); |
---|
594 | |
---|
595 | assert (nbp->hostname != 0 && nbp->pathname != 0); |
---|
596 | assert (nbp->spare != 0); |
---|
597 | if (fprintf (new_file, format, |
---|
598 | nbp->status, nbp->date_attended, nbp->last, |
---|
599 | nbp->hostname, nbp->pathname, |
---|
600 | temp, nbp->spare) == EOF) { |
---|
601 | free (temp); |
---|
602 | goto punt; |
---|
603 | } |
---|
604 | free (temp); |
---|
605 | } |
---|
606 | } |
---|
607 | enddbent(); |
---|
608 | /* Fsync the file, just to be sure */ |
---|
609 | fflush(new_file); |
---|
610 | if (fsync (fileno (new_file)) == -1) |
---|
611 | goto punt; |
---|
612 | if (ferror (new_file)) { |
---|
613 | *result = CANT_WRITE_TEMP; |
---|
614 | goto punt; |
---|
615 | } |
---|
616 | if (fclose (new_file)) { |
---|
617 | *result = CANT_WRITE_TEMP; |
---|
618 | goto punt; |
---|
619 | } |
---|
620 | new_file = NULL; |
---|
621 | *result = (rename(new_name, old_name) < 0) ? errno : 0; |
---|
622 | if (*result) |
---|
623 | (void) unlink (new_name); |
---|
624 | new_file = NULL; |
---|
625 | free(new_name); |
---|
626 | free(old_name); |
---|
627 | free(touched); |
---|
628 | return; |
---|
629 | |
---|
630 | punt: |
---|
631 | if (new_file) |
---|
632 | fclose(new_file); |
---|
633 | enddbent(); |
---|
634 | unlink(new_name); |
---|
635 | free(new_name); |
---|
636 | free(old_name); |
---|
637 | free(touched); |
---|
638 | return; |
---|
639 | } |
---|