]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/filedir.c
CNID/DID patch from Uwe Hees (moderately tested)
[netatalk.git] / etc / afpd / filedir.c
1 /*
2  * $Id: filedir.c,v 1.11 2001-08-14 14:00:10 rufustfirefly Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <errno.h>
13 #include <sys/syslog.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/param.h>
17 #include <netatalk/endian.h>
18 #include <atalk/adouble.h>
19 #include <atalk/afp.h>
20 #include <atalk/util.h>
21 #ifdef CNID_DB
22 #include <atalk/cnid.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif /* HAVE_FCNTL_H */
29 #include <dirent.h>
30 #include <string.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif /* HAVE_UNISTD_H */
34
35 #include "directory.h"
36 #include "desktop.h"
37 #include "volume.h"
38 #include "fork.h"
39 #include "file.h"
40 #include "globals.h"
41 #include "filedir.h"
42
43 int matchfile2dirperms(upath, vol, did)
44                               /* Since it's kinda' big; I decided against an
45                               inline function */
46     char        *upath;
47     struct vol  *vol;
48     int         did;
49   /* The below code changes the way file ownership is determined in the name of
50   fixing dropboxes.  It has known security problem.  See the netatalk FAQ for
51   more information */
52 {
53     struct stat st, sb;
54     struct dir  *dir;
55     char        adpath[50];
56     int         uid;
57
58 #ifdef DEBUG
59     syslog (LOG_INFO, "begin matchfile2dirperms:");
60 #endif /* DEBUG */
61
62     if (stat(upath, &st ) < 0)
63       syslog(LOG_ERR, "Could not stat %s: %m", upath);
64     strcpy (adpath, "./.AppleDouble/");
65     strcat (adpath, upath);
66     if (( dir = dirsearch( vol, did )) == NULL ) {
67       syslog (LOG_ERR, "matchfile2dirperms: Unable to get directory info.");
68       return( AFPERR_NOOBJ );
69     }
70     else if (stat(".", &sb) < 0) {
71         syslog (LOG_ERR, 
72            "matchfile2dirperms: Error checking directory \"%s\": %m", 
73            dir->d_name);
74         return(AFPERR_NOOBJ );
75       }
76     else {
77         uid=geteuid();
78         if ( uid != sb.st_uid )
79         {
80           seteuid(0);
81           if (lchown(upath, sb.st_uid, sb.st_gid) < 0)
82           {
83             syslog (LOG_ERR, 
84               "matchfile2dirperms: Error changing owner/gid of %s: %m", upath);
85             return (AFPERR_ACCESS);
86           }
87           if (chmod(upath,(st.st_mode&0x0FFFF)| S_IRGRP| S_IROTH) < 0)
88           {
89             syslog (LOG_ERR, 
90               "matchfile2dirperms:  Error adding file read permissions: %m");
91             return (AFPERR_ACCESS);
92           }
93 #ifdef DEBUG
94           else 
95             syslog (LOG_INFO, 
96               "matchfile2dirperms:  Added S_IRGRP and S_IROTH: %m");
97 #endif /* DEBUG */
98           if (lchown(adpath, sb.st_uid, sb.st_gid) < 0)
99           {
100             syslog (LOG_ERR, 
101               "matchfile2dirperms: Error changing AppleDouble owner/gid %s: %m",
102               adpath);
103             return (AFPERR_ACCESS);
104           }
105           if (chmod(adpath, (st.st_mode&0x0FFFF)| S_IRGRP| S_IROTH) < 0)
106           {
107             syslog (LOG_ERR, 
108               "matchfile2dirperms:  Error adding AD file read permissions: %m");
109             return (AFPERR_ACCESS);
110           }
111 #ifdef DEBUG
112           else 
113             syslog (LOG_INFO, 
114               "matchfile2dirperms:  Added S_IRGRP and S_IROTH to AD: %m");
115 #endif /* DEBUG */
116         }
117 #ifdef DEBUG
118         else
119           syslog (LOG_INFO, 
120             "matchfile2dirperms: No ownership change necessary.");
121 #endif /* DEBUG */
122     } /* end else if stat success */
123     seteuid(uid); /* Restore process ownership to normal */
124 #ifdef DEBUG
125     syslog (LOG_INFO, "end matchfile2dirperms:");
126 #endif /* DEBUG */
127
128     return (AFP_OK);
129
130 }
131     
132
133 int afp_getfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
134     AFPObj      *obj;
135     char        *ibuf, *rbuf;
136     int         ibuflen, *rbuflen;
137 {
138     struct stat         st;
139     struct vol          *vol;
140     struct dir          *dir;
141     u_int32_t           did;
142     int                 buflen, ret;
143     char                *path;
144     u_int16_t           fbitmap, dbitmap, vid;
145
146 #ifdef DEBUG
147     syslog(LOG_INFO, "begin afp_getfildirparams:");
148 #endif /* DEBUG */
149
150     *rbuflen = 0;
151     ibuf += 2;
152
153     memcpy( &vid, ibuf, sizeof( vid ));
154     ibuf += sizeof( vid );
155     if (( vol = getvolbyvid( vid )) == NULL ) {
156         return( AFPERR_PARAM );
157     }
158
159     memcpy( &did, ibuf, sizeof( did ));
160     ibuf += sizeof( did );
161
162     if (( dir = dirsearch( vol, did )) == NULL ) {
163         return( AFPERR_NOOBJ );
164     }
165
166     memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
167     fbitmap = ntohs( fbitmap );
168     ibuf += sizeof( fbitmap );
169     memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
170     dbitmap = ntohs( dbitmap );
171     ibuf += sizeof( dbitmap );
172
173     if (( path = cname( vol, dir, &ibuf )) == NULL) {
174         return( AFPERR_NOOBJ );
175     }
176
177     if ( stat( mtoupath(vol, path ), &st ) < 0 ) {
178         return( AFPERR_NOOBJ );
179     }
180
181     buflen = 0;
182     if (S_ISDIR(st.st_mode)) {
183         if (dbitmap && ( ret = getdirparams(vol, dbitmap, ".", curdir,
184                 &st, rbuf + 3 * sizeof( u_int16_t ), &buflen )) != AFP_OK ) {
185             return( ret );
186         }
187         /* this is a directory */
188         *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISDIR; 
189     } else {
190         if (fbitmap && ( ret = getfilparams(vol, fbitmap, path, curdir, &st,
191                 rbuf + 3 * sizeof( u_int16_t ), &buflen )) != AFP_OK ) {
192             return( ret );
193         }
194         /* this is a file */
195         *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISFILE;
196     }
197     *rbuflen = buflen + 3 * sizeof( u_int16_t );
198     fbitmap = htons( fbitmap );
199     memcpy( rbuf, &fbitmap, sizeof( fbitmap ));
200     rbuf += sizeof( fbitmap );
201     dbitmap = htons( dbitmap );
202     memcpy( rbuf, &dbitmap, sizeof( dbitmap ));
203     rbuf += sizeof( dbitmap ) + sizeof( u_char );
204     *rbuf = 0;
205
206 #ifdef DEBUG
207     syslog(LOG_INFO, "end afp_getfildirparams:");
208 #endif /* DEBUG */
209
210     return( AFP_OK );
211 }
212
213 int afp_setfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
214     AFPObj      *obj;
215     char        *ibuf, *rbuf;
216     int         ibuflen, *rbuflen;
217 {
218     struct stat st;
219     struct vol  *vol;
220     struct dir  *dir;
221     char        *path;
222     u_int16_t   vid, bitmap;
223     int         did, rc;
224
225 #ifdef DEBUG
226     syslog(LOG_INFO, "begin afp_setfildirparams:");
227 #endif /* DEBUG */
228
229     *rbuflen = 0;
230     ibuf += 2;
231     memcpy( &vid, ibuf, sizeof(vid));
232     ibuf += sizeof( vid );
233
234     if (( vol = getvolbyvid( vid )) == NULL ) {
235         return( AFPERR_PARAM );
236     }
237
238     if (vol->v_flags & AFPVOL_RO)
239         return AFPERR_VLOCK;
240
241     memcpy( &did, ibuf, sizeof( did));
242     ibuf += sizeof( did);
243
244     if (( dir = dirsearch( vol, did )) == NULL ) {
245         return( AFPERR_NOOBJ );
246     }
247
248     memcpy( &bitmap, ibuf, sizeof( bitmap ));
249     bitmap = ntohs( bitmap );
250     ibuf += sizeof( bitmap );
251
252     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
253         return( AFPERR_NOOBJ );
254     }
255
256     if ( stat( mtoupath(vol, path ), &st ) < 0 ) {
257         return( AFPERR_NOOBJ );
258     }
259
260     /*
261      * If ibuf is odd, make it even.
262      */
263     if ((u_long)ibuf & 1 ) {
264         ibuf++;
265     }
266
267     if (S_ISDIR(st.st_mode)) {
268         rc = setdirparams(vol, path, bitmap, ibuf );
269     } else {
270         rc = setfilparams(vol, path, bitmap, ibuf );
271     }
272     if ( rc == AFP_OK ) {
273         setvoltime(obj, vol );
274     }
275
276 #ifdef DEBUG
277     syslog(LOG_INFO, "end afp_setfildirparams:");
278 #endif /* DEBUG */
279
280     return( rc );
281 }
282
283 int afp_rename(obj, ibuf, ibuflen, rbuf, rbuflen )
284     AFPObj      *obj;
285     char        *ibuf, *rbuf;
286     int         ibuflen, *rbuflen;
287 {
288     struct adouble      ad;
289     struct stat         st;
290     struct vol          *vol;
291     struct dir          *dir, *odir = NULL;
292     char                *path, *buf, *upath, *newpath;
293     char                *newadpath;
294     u_int32_t           did;
295     int                 plen;
296     u_int16_t           vid;
297 #ifdef CNID_DB
298     cnid_t              id;
299 #endif /* CNID_DB */
300
301 #ifdef DEBUG
302     syslog(LOG_INFO, "begin afp_rename:");
303 #endif /* DEBUG */
304
305     *rbuflen = 0;
306     ibuf += 2;
307
308     memcpy( &vid, ibuf, sizeof( vid ));
309     ibuf += sizeof( vid );
310     if (( vol = getvolbyvid( vid )) == NULL ) {
311         return( AFPERR_PARAM );
312     }
313
314     if (vol->v_flags & AFPVOL_RO)
315         return AFPERR_VLOCK;
316
317     memcpy( &did, ibuf, sizeof( did ));
318     ibuf += sizeof( did );
319     if (( dir = dirsearch( vol, did )) == NULL ) {
320         return( AFPERR_NOOBJ );
321     }
322
323     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
324         return( AFPERR_NOOBJ );
325     }
326
327     /* another place where we know about the path type */
328     if ( *ibuf++ != 2 ) {
329         return( AFPERR_PARAM );
330     }
331     plen = (unsigned char) *ibuf++;
332     *( ibuf + plen ) = '\0';
333
334     if ( *path == '\0' ) {
335         if ( curdir->d_parent == NULL ) { /* root directory */
336             return( AFPERR_NORENAME );
337         }
338         odir = curdir;
339         path = curdir->d_name;
340         if ( movecwd( vol, curdir->d_parent ) < 0 ) {
341             return( AFPERR_NOOBJ );
342         }
343     }
344
345 #ifdef notdef
346     if ( strcasecmp( path, ibuf ) == 0 ) {
347         return( AFP_OK );
348     }
349 #endif /* notdef */
350
351     /* if a curdir/newname ofork exists, return busy */
352     if (of_findname(vol, curdir, ibuf))
353         return AFPERR_BUSY;
354
355     /* source == destination. just say okay. */
356     if (strcmp(path, ibuf) == 0)
357         return AFP_OK;
358
359     /* check for illegal characters */
360     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
361         strpbrk(ibuf, MSWINDOWS_BADCHARS))
362         return AFPERR_PARAM;
363
364     newpath = obj->oldtmp;
365     strcpy( newpath, mtoupath(vol, ibuf ));
366
367     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(newpath, '/'))
368       return AFPERR_PARAM;
369
370     if (!validupath(vol, newpath))
371       return AFPERR_EXIST;
372
373     /* the strdiacasecmp deals with case-insensitive, case preserving
374        filesystems */
375     if (stat( newpath, &st ) == 0 && strdiacasecmp(path, ibuf))
376         return( AFPERR_EXIST );
377
378     upath = mtoupath(vol, path);
379
380 #ifdef CNID_DB
381     id = cnid_get(vol->v_db, curdir->d_did, upath, strlen(upath));
382 #endif /* CNID_DB */
383
384     if ( rename( upath, newpath ) < 0 ) {
385         switch ( errno ) {
386         case ENOENT :
387             return( AFPERR_NOOBJ );
388         case EACCES :
389             return( AFPERR_ACCESS );
390         default :
391             return( AFPERR_PARAM );
392         }
393     }
394
395 #ifdef CNID_DB
396     if (stat(newpath, &st) < 0) /* this shouldn't fail */
397       return AFPERR_MISC;
398     cnid_update(vol->v_db, id, &st, curdir->d_did, newpath, strlen(newpath));
399 #endif /* CNID_DB */
400
401     if ( !odir ) {
402         newadpath = obj->newtmp;
403         strcpy( newadpath, ad_path( newpath, 0 ));
404         if ( rename( ad_path( upath, 0 ), newadpath ) < 0 ) {
405             if ( errno == ENOENT ) {    /* no adouble header file */
406                 if (( unlink( newadpath ) < 0 ) && ( errno != ENOENT )) {
407                     return( AFPERR_PARAM );
408                 }
409                 goto out;
410             }
411             return( AFPERR_PARAM );
412         }
413
414         memset(&ad, 0, sizeof(ad));
415         if ( ad_open( newpath, ADFLAGS_HF, O_RDWR|O_CREAT, 0666,
416                       &ad) < 0 ) {
417             return( AFPERR_PARAM );
418         }
419     } else {
420         int isad = 1;
421
422         memset(&ad, 0, sizeof(ad));
423         if ( ad_open( newpath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR, 
424                       O_RDWR|O_CREAT, 0666, &ad) < 0 ) {
425             if (!((errno == ENOENT) && vol_noadouble(vol)))
426               return( AFPERR_PARAM );
427             isad = 0;
428         }
429         if ((buf = realloc( odir->d_name, plen + 1 )) == NULL ) {
430             syslog( LOG_ERR, "afp_rename: realloc: %m" );
431             if (isad) {
432               ad_flush(&ad, ADFLAGS_HF); /* in case of create */
433               ad_close(&ad, ADFLAGS_HF);
434             }
435             return AFPERR_MISC;
436         }
437         odir->d_name = buf;
438         strcpy( odir->d_name, ibuf );
439         if (!isad)
440           goto out;
441     }
442
443     ad_setentrylen( &ad, ADEID_NAME, plen );
444     memcpy( ad_entry( &ad, ADEID_NAME ), ibuf, plen );
445     ad_flush( &ad, ADFLAGS_HF );
446     ad_close( &ad, ADFLAGS_HF );
447
448 out:
449     setvoltime(obj, vol );
450
451     /* if it's still open, rename the ofork as well. */
452     if (of_rename(vol, curdir, path, curdir, ibuf) < 0)
453         return AFPERR_MISC;
454
455 #ifdef DEBUG
456     syslog(LOG_INFO, "end afp_rename:");
457 #endif /* DEBUG */
458
459     return( AFP_OK );
460 }
461
462
463 int afp_delete(obj, ibuf, ibuflen, rbuf, rbuflen )
464     AFPObj      *obj;
465     char        *ibuf, *rbuf;
466     int         ibuflen, *rbuflen;
467 {
468     struct vol          *vol;
469     struct dir          *dir;
470     char                *path, *upath;
471     int                 did, rc;
472     u_int16_t           vid;
473
474 #ifdef DEBUG
475     syslog(LOG_INFO, "begin afp_delete:");
476 #endif /* DEBUG */ 
477
478     *rbuflen = 0;
479     ibuf += 2;
480
481     memcpy( &vid, ibuf, sizeof( vid ));
482     ibuf += sizeof( vid );
483     if (( vol = getvolbyvid( vid )) == NULL ) {
484         return( AFPERR_PARAM );
485     }
486
487     if (vol->v_flags & AFPVOL_RO)
488         return AFPERR_VLOCK;
489
490     memcpy( &did, ibuf, sizeof( did ));
491     ibuf += sizeof( int );
492     if (( dir = dirsearch( vol, did )) == NULL ) {
493         return( AFPERR_NOOBJ );
494     }
495
496     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
497         return( AFPERR_NOOBJ );
498     }
499
500     if ( *path == '\0' ) {
501         rc = deletecurdir( vol, obj->oldtmp, AFPOBJ_TMPSIZ);
502     } else if (of_findname(vol, curdir, path)) {
503         rc = AFPERR_BUSY;
504     } else if ((rc = deletefile( upath = mtoupath(vol, path ))) == AFP_OK) {
505 #ifdef CNID_DB /* get rid of entry */
506         cnid_t id = cnid_get(vol->v_db, curdir->d_did, upath, strlen(upath));
507         cnid_delete(vol->v_db, id);
508 #endif /* CNID_DB */
509     }
510     if ( rc == AFP_OK ) {
511         setvoltime(obj, vol );
512     }
513
514 #ifdef DEBUG
515     syslog(LOG_INFO, "end afp_delete:");
516 #endif /* DEBUG */
517
518     return( rc );
519 }
520
521 char *ctoupath( vol, dir, name )
522     const struct vol    *vol;
523     struct dir  *dir;
524     char        *name;
525 {
526     struct dir  *d;
527     static char path[ MAXPATHLEN + 1];
528     char        *p, *u;
529     int         len;
530
531     p = path + sizeof( path ) - 1;
532     *p = '\0';
533     u = mtoupath(vol, name );
534     len = strlen( u );
535     p -= len;
536     strncpy( p, u, len );
537     for ( d = dir; d->d_parent; d = d->d_parent ) {
538         *--p = '/';
539         u = mtoupath(vol, d->d_name );
540         len = strlen( u );
541         p -= len;
542         strncpy( p, u, len );
543     }
544     *--p = '/';
545     len = strlen( vol->v_path );
546     p -= len;
547     strncpy( p, vol->v_path, len );
548
549     return( p );
550 }
551
552
553 int afp_moveandrename(obj, ibuf, ibuflen, rbuf, rbuflen )
554     AFPObj      *obj;
555     char        *ibuf, *rbuf;
556     int         ibuflen, *rbuflen;
557 {
558     struct vol  *vol;
559     struct dir  *sdir, *ddir, *odir = NULL;
560     struct stat st;
561     char        *oldname, *newname;
562     char        *path, *p, *upath; 
563     int         did, rc;
564     int         plen;
565     u_int16_t   vid;
566 #ifdef CNID_DB
567     cnid_t      id;
568 #endif /* CNID_DB */
569 #ifdef DROPKLUDGE
570     int         retvalue;
571 #endif /* DROPKLUDGE */
572
573 #ifdef DEBUG
574     syslog(LOG_INFO, "begin afp_moveandrename:");
575 #endif /* DEBUG */
576
577     *rbuflen = 0;
578     ibuf += 2;
579
580     memcpy( &vid, ibuf, sizeof( vid ));
581     ibuf += sizeof( vid );
582     if (( vol = getvolbyvid( vid )) == NULL ) {
583         return( AFPERR_PARAM );
584     }
585
586     if (vol->v_flags & AFPVOL_RO)
587         return AFPERR_VLOCK;
588
589     /* source did followed by dest did */
590     memcpy( &did, ibuf, sizeof( did ));
591     ibuf += sizeof( int );
592     if (( sdir = dirsearch( vol, did )) == NULL ) {
593         return( AFPERR_PARAM );
594     }
595
596     memcpy( &did, ibuf, sizeof( did ));
597     ibuf += sizeof( int );
598
599     /* source pathname */
600     if (( path = cname( vol, sdir, &ibuf )) == NULL ) {
601         return( AFPERR_NOOBJ );
602     }
603
604     sdir = curdir;
605     newname = obj->newtmp;
606     oldname = obj->oldtmp;
607     if ( *path != '\0' ) {
608         /* not a directory */
609         strcpy(newname, path);
610         strcpy(oldname, path); /* an extra copy for of_rename */
611 #ifdef CNID_DB
612         p = mtoupath(vol, path);
613         id = cnid_get(vol->v_db, sdir->d_did, p, strlen(p));
614 #endif /* CNID_DB */
615         p = ctoupath( vol, sdir, newname );
616     } else {
617         odir = curdir;
618         strcpy( newname, odir->d_name );
619         strcpy(oldname, odir->d_name);
620         p = ctoupath( vol, odir->d_parent, newname );
621 #ifdef CNID_DB
622         id = curdir->d_did; /* we already have the CNID */
623 #endif /* CNID_DB */
624     }
625     /*
626      * p now points to the full pathname of the source fs object.
627      */
628
629     /* get the destination directory */
630     if (( ddir = dirsearch( vol, did )) == NULL ) {
631         return( AFPERR_PARAM );
632     }
633     if (( path = cname( vol, ddir, &ibuf )) == NULL ) {
634         return( AFPERR_NOOBJ );
635     }
636     if ( *path != '\0' ) {
637         return( AFPERR_BADTYPE );
638     }
639
640     /* one more place where we know about path type */
641     if ( *ibuf++ != 2 ) {
642         return( AFPERR_PARAM );
643     }
644
645     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
646         strncpy( newname, ibuf, plen );
647         newname[ plen ] = '\0';
648     }
649
650     /* check for illegal characters */
651     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
652         strpbrk(newname, MSWINDOWS_BADCHARS))
653         return AFPERR_PARAM;
654
655     upath = mtoupath(vol, newname);
656
657     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
658       return AFPERR_PARAM;
659
660     if (!validupath(vol, upath))
661       return AFPERR_EXIST;
662
663     /* source == destination. we just silently accept this. */
664     if (curdir == sdir) {
665       if (strcmp(oldname, newname) == 0)
666         return AFP_OK;
667       
668       /* deal with case insensitive, case-preserving filesystems. */
669       if ((stat(upath, &st) == 0) && strdiacasecmp(oldname, newname)) 
670         return AFPERR_EXIST;
671       
672     } else if (stat(upath, &st ) == 0)
673       return( AFPERR_EXIST );
674       
675     if ( !odir ) {
676       if (of_findname(vol, curdir, newname)) {
677         rc = AFPERR_BUSY;
678       } else if ((rc = renamefile( p, upath, newname, 
679                                    vol_noadouble(vol) )) == AFP_OK) {
680         /* if it's still open, rename the ofork as well. */
681         rc = of_rename(vol, sdir, oldname, curdir, newname);
682       }
683     } else {
684         rc = renamedir(p, upath, odir, curdir, newname, vol_noadouble(vol));
685     }
686
687 #ifdef DROPKLUDGE
688     if (vol->v_flags & AFPVOL_DROPBOX) {
689         if (retvalue=matchfile2dirperms (newname, vol, did) != AFP_OK) {
690             return retvalue;
691         }
692     }
693 #endif /* DROPKLUDGE */
694
695     if ( rc == AFP_OK ) {
696 #ifdef CNID_DB
697         /* renaming may have moved the file/dir across a filesystem */
698         if (stat(upath, &st) < 0)
699           return AFPERR_MISC;
700
701         /* fix up the catalog entry */
702         cnid_update(vol->v_db, id, &st, curdir->d_did, upath, strlen(upath));
703 #endif /* CNID_DB */
704         setvoltime(obj, vol );
705     }
706
707 #ifdef DEBUG
708     syslog(LOG_INFO, "end afp_moveandrename:");
709 #endif /* DEBUG */
710
711     return( rc );
712 }
713