]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
fix FreeBSD 4.9 compile
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.92.2.2.2.17 2004-03-04 23:57:20 bfernhomberg 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 <stdio.h>
13 #include <stdlib.h>
14
15 /* STDC check */
16 #if STDC_HEADERS
17 #include <string.h>
18 #else /* STDC_HEADERS */
19 #ifndef HAVE_STRCHR
20 #define strchr index
21 #define strrchr index
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
24
25 #ifndef HAVE_MEMCPY
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
30
31 #include <atalk/adouble.h>
32 #include <utime.h>
33 #include <dirent.h>
34 #include <errno.h>
35
36 #include <atalk/logger.h>
37 #include <sys/param.h>
38
39
40 #include <atalk/afp.h>
41 #include <atalk/util.h>
42 #include <atalk/cnid.h>
43 #include "directory.h"
44 #include "desktop.h"
45 #include "volume.h"
46 #include "fork.h"
47 #include "file.h"
48 #include "filedir.h"
49 #include "globals.h"
50 #include "unix.h"
51
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53  * field         bytes        subfield    bytes
54  * 
55  * files:
56  * ioFlFndrInfo  16      ->       type    4  type field
57  *                             creator    4  creator field
58  *                               flags    2  finder flags:
59  *                                           alias, bundle, etc.
60  *                            location    4  location in window
61  *                              folder    2  window that contains file
62  * 
63  * ioFlXFndrInfo 16      ->     iconID    2  icon id
64  *                              unused    6  reserved 
65  *                              script    1  script system
66  *                              xflags    1  reserved
67  *                           commentID    2  comment id
68  *                           putawayID    4  home directory id
69  */
70
71 const u_char ufinderi[] = {
72                               'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
73                               0, 0, 0, 0, 0, 0, 0, 0,
74                               0, 0, 0, 0, 0, 0, 0, 0,
75                               0, 0, 0, 0, 0, 0, 0, 0
76                           };
77
78 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
79 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
80 {
81     struct extmap       *em;
82     void                *ad_finder;
83
84     if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
85         memcpy(data, ad_finder, 32);
86     }
87     else {
88         memcpy(data, ufinderi, 32);
89     }
90
91     if ((!adp  || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 )) 
92                 && (em = getextmap( mpath ))
93     ) {
94         memcpy(data, em->em_type, sizeof( em->em_type ));
95         memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
96     }
97     return data;
98 }
99
100 /* ---------------------
101 */
102 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8) 
103 {
104     u_int32_t   aint;
105     char        *tp = NULL;
106     char        *src = name;
107     aint = strlen( name );
108
109     if (!utf8) {
110         /* want mac name */
111         if (utf8_encoding()) {
112             /* but name is an utf8 mac name */
113             char *u, *m;
114            
115             /* global static variable... */
116             tp = strdup(name);
117             if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
118                aint = 0;
119             }
120             else {
121                 aint = strlen(m);
122                 src = m;
123             }
124             
125         }
126         if (aint > MACFILELEN)
127             aint = MACFILELEN;
128         *data++ = aint;
129     }
130     else {
131         u_int16_t temp;
132
133         if (aint > 255)  /* FIXME safeguard, anyway if no ascii char it's game over*/
134            aint = 255;
135
136         utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0;         /* htonl(utf8) */
137         memcpy(data, &utf8, sizeof(utf8));
138         data += sizeof(utf8);
139         
140         temp = htons(aint);
141         memcpy(data, &temp, sizeof(temp));
142         data += sizeof(temp);
143     }
144
145     memcpy( data, src, aint );
146     data += aint;
147     if (tp) {
148         strcpy(name, tp);
149         free(tp);
150     }
151     return data;
152 }
153
154 /*
155  * FIXME: PDINFO is UTF8 and doesn't need adp
156 */
157 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR)  |\
158                                   (1 << FILPBIT_CDATE) |\
159                                   (1 << FILPBIT_MDATE) |\
160                                   (1 << FILPBIT_BDATE) |\
161                                   (1 << FILPBIT_FINFO) |\
162                                   (1 << FILPBIT_RFLEN) |\
163                                   (1 << FILPBIT_EXTRFLEN) |\
164                                   (1 << FILPBIT_PDINFO)))
165
166 /* -------------------------- */
167 u_int32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
168              const cnid_t did, const char *upath, const int len) 
169 {
170 u_int32_t aint = 0;
171
172 #if AD_VERSION > AD_VERSION1
173 dev_t  dev;
174 ino_t  ino;
175 cnid_t a_did;
176 char   stamp[ADEDLEN_PRIVSYN];
177     /* look in AD v2 header 
178      * note inode and device are opaques and not in network order
179     */
180     if (adp && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)) {
181         memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
182         if ( sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)) {
183             memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
184             if (sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)) {
185                 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
186                 if (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)) {
187                     memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
188
189                     if (   ((vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
190                            && ino == st->st_ino && a_did == did &&
191                            !memcmp(vol->v_stamp, stamp, sizeof(stamp)) &&
192                            (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)) ) 
193                     { 
194                         memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
195                         return aint;
196                     } 
197                 }
198             }
199         }
200     }
201 #endif
202     if (vol->v_cdb != NULL) {
203             aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
204             /* Throw errors if cnid_add fails. */
205             if (aint == CNID_INVALID) {
206             switch (errno) {
207             case CNID_ERR_CLOSE: /* the db is closed */
208                 break;
209             case CNID_ERR_PARAM:
210                 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
211                 afp_errno = AFPERR_PARAM;
212                 return CNID_INVALID;
213             case CNID_ERR_PATH:
214                 afp_errno = AFPERR_PARAM;
215                 return CNID_INVALID;
216             default:
217                 afp_errno = AFPERR_MISC;
218                 return CNID_INVALID;
219             }
220         }
221 #if AD_VERSION > AD_VERSION1
222         else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
223             /* update the ressource fork
224              * for a folder adp is always null
225              */
226             ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
227             ad_flush(adp, ADFLAGS_HF);
228         }
229 #endif    
230     }
231     return aint;
232 }
233              
234 /* -------------------------- */
235 int getmetadata(struct vol *vol,
236                  u_int16_t bitmap,
237                  struct path *path, struct dir *dir, 
238                  char *buf, int *buflen, struct adouble *adp, int attrbits )
239 {
240     char                *data, *l_nameoff = NULL, *upath;
241     char                *utf_nameoff = NULL;
242     int                 bit = 0;
243     u_int32_t           aint;
244     cnid_t              id = 0;
245     u_int16_t           ashort;
246     u_char              achar, fdType[4];
247     u_int32_t           utf8 = 0;
248     struct stat         *st;
249     struct maccess      ma;
250
251 #ifdef DEBUG
252     LOG(log_info, logtype_afpd, "begin getmetadata:");
253 #endif /* DEBUG */
254
255     upath = path->u_name;
256     st = &path->st;
257
258     data = buf;
259
260     if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
261          || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
262          || (bitmap & (1 << FILPBIT_FNUM))) {
263          
264         id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
265         if (id == 0)
266             return afp_errno;
267         if (!path->m_name) {
268             path->m_name = utompath(vol, upath, id, utf8_encoding());
269         }
270     }
271     while ( bitmap != 0 ) {
272         while (( bitmap & 1 ) == 0 ) {
273             bitmap = bitmap>>1;
274             bit++;
275         }
276
277         switch ( bit ) {
278         case FILPBIT_ATTR :
279             if ( adp ) {
280                 ad_getattr(adp, &ashort);
281             } else if (*upath == '.') {
282                 ashort = htons(ATTRBIT_INVISIBLE);
283             } else
284                 ashort = 0;
285 #if 0
286             /* FIXME do we want a visual clue if the file is read only
287              */
288             struct maccess      ma;
289             accessmode( ".", &ma, dir , NULL);
290             if ((ma.ma_user & AR_UWRITE)) {
291                 accessmode( upath, &ma, dir , st);
292                 if (!(ma.ma_user & AR_UWRITE)) {
293                         attrbits |= ATTRBIT_NOWRITE;
294                 }
295             }
296 #endif
297             if (attrbits)
298                 ashort = htons(ntohs(ashort) | attrbits);
299             memcpy(data, &ashort, sizeof( ashort ));
300             data += sizeof( ashort );
301             break;
302
303         case FILPBIT_PDID :
304             memcpy(data, &dir->d_did, sizeof( u_int32_t ));
305             data += sizeof( u_int32_t );
306             break;
307
308         case FILPBIT_CDATE :
309             if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
310                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
311             memcpy(data, &aint, sizeof( aint ));
312             data += sizeof( aint );
313             break;
314
315         case FILPBIT_MDATE :
316             if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
317                 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
318                    aint = AD_DATE_FROM_UNIX(st->st_mtime);
319                 }
320             } else {
321                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
322             }
323             memcpy(data, &aint, sizeof( int ));
324             data += sizeof( int );
325             break;
326
327         case FILPBIT_BDATE :
328             if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
329                 aint = AD_DATE_START;
330             memcpy(data, &aint, sizeof( int ));
331             data += sizeof( int );
332             break;
333
334         case FILPBIT_FINFO :
335             get_finderinfo(path->m_name, adp, (char *)data);
336             if (!adp) {
337                 if (*upath == '.') { /* make it invisible */
338                     ashort = htons(FINDERINFO_INVISIBLE);
339                     memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
340                 }
341             }
342             data += 32;
343             break;
344
345         case FILPBIT_LNAME :
346             l_nameoff = data;
347             data += sizeof( u_int16_t );
348             break;
349
350         case FILPBIT_SNAME :
351             memset(data, 0, sizeof(u_int16_t));
352             data += sizeof( u_int16_t );
353             break;
354
355         case FILPBIT_FNUM :
356             memcpy(data, &id, sizeof( id ));
357             data += sizeof( id );
358             break;
359
360         case FILPBIT_DFLEN :
361             if  (st->st_size > 0xffffffff)
362                aint = 0xffffffff;
363             else
364                aint = htonl( st->st_size );
365             memcpy(data, &aint, sizeof( aint ));
366             data += sizeof( aint );
367             break;
368
369         case FILPBIT_RFLEN :
370             if ( adp ) {
371                 if (adp->ad_rlen > 0xffffffff)
372                     aint = 0xffffffff;
373                 else
374                     aint = htonl( adp->ad_rlen);
375             } else {
376                 aint = 0;
377             }
378             memcpy(data, &aint, sizeof( aint ));
379             data += sizeof( aint );
380             break;
381
382             /* Current client needs ProDOS info block for this file.
383                Use simple heuristic and let the Mac "type" string tell
384                us what the PD file code should be.  Everything gets a
385                subtype of 0x0000 unless the original value was hashed
386                to "pXYZ" when we created it.  See IA, Ver 2.
387                <shirsch@adelphia.net> */
388         case FILPBIT_PDINFO :
389             if (afp_version >= 30) { /* UTF8 name */
390                 utf8 = kTextEncodingUTF8;
391                 utf_nameoff = data;
392                 data += sizeof( u_int16_t );
393                 aint = 0;
394                 memcpy(data, &aint, sizeof( aint ));
395                 data += sizeof( aint );
396             }
397             else {
398                 if ( adp ) {
399                     memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
400
401                     if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
402                         achar = '\x04';
403                         ashort = 0x0000;
404                     }
405                     else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
406                         achar = '\xff';
407                         ashort = 0x0000;
408                     }
409                     else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
410                         achar = '\xb3';
411                         ashort = 0x0000;
412                     }
413                     else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
414                         achar = '\x00';
415                         ashort = 0x0000;
416                     }
417                     else if ( fdType[0] == 'p' ) {
418                         achar = fdType[1];
419                         ashort = (fdType[2] * 256) + fdType[3];
420                     }
421                     else {
422                         achar = '\x00';
423                         ashort = 0x0000;
424                     }
425                 }
426                 else {
427                     achar = '\x00';
428                     ashort = 0x0000;
429                 }
430
431                 *data++ = achar;
432                 *data++ = 0;
433                 memcpy(data, &ashort, sizeof( ashort ));
434                 data += sizeof( ashort );
435                 memset(data, 0, sizeof( ashort ));
436                 data += sizeof( ashort );
437             }
438             break;
439         case FILPBIT_EXTDFLEN:
440             aint = htonl(st->st_size >> 32);
441             memcpy(data, &aint, sizeof( aint ));
442             data += sizeof( aint );
443             aint = htonl(st->st_size);
444             memcpy(data, &aint, sizeof( aint ));
445             data += sizeof( aint );
446             break;
447         case FILPBIT_EXTRFLEN:
448             aint = 0;
449             if (adp) 
450                 aint = htonl(adp->ad_rlen >> 32);
451             memcpy(data, &aint, sizeof( aint ));
452             data += sizeof( aint );
453             if (adp) 
454                 aint = htonl(adp->ad_rlen);
455             memcpy(data, &aint, sizeof( aint ));
456             data += sizeof( aint );
457             break;
458         case FILPBIT_UNIXPR :
459             aint = htonl(st->st_uid);
460             memcpy( data, &aint, sizeof( aint ));
461             data += sizeof( aint );
462             aint = htonl(st->st_gid);
463             memcpy( data, &aint, sizeof( aint ));
464             data += sizeof( aint );
465
466             aint = htonl(st->st_mode);
467             memcpy( data, &aint, sizeof( aint ));
468             data += sizeof( aint );
469
470             accessmode( upath, &ma, dir , st);
471
472             *data++ = ma.ma_user;
473             *data++ = ma.ma_world;
474             *data++ = ma.ma_group;
475             *data++ = ma.ma_owner;
476             break;
477
478         default :
479             return( AFPERR_BITMAP );
480         }
481         bitmap = bitmap>>1;
482         bit++;
483     }
484     if ( l_nameoff ) {
485         ashort = htons( data - buf );
486         memcpy(l_nameoff, &ashort, sizeof( ashort ));
487         data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
488     }
489     if ( utf_nameoff ) {
490         ashort = htons( data - buf );
491         memcpy(utf_nameoff, &ashort, sizeof( ashort ));
492         data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
493     }
494     *buflen = data - buf;
495     return (AFP_OK);
496 }
497                 
498 /* ----------------------- */
499 int getfilparams(struct vol *vol,
500                  u_int16_t bitmap,
501                  struct path *path, struct dir *dir, 
502                  char *buf, int *buflen )
503 {
504     struct adouble      ad, *adp;
505     struct ofork        *of;
506     char                    *upath;
507     u_int16_t           attrbits = 0;
508     int                 opened = 0;
509     int rc;    
510
511 #ifdef DEBUG
512     LOG(log_info, logtype_default, "begin getfilparams:");
513 #endif /* DEBUG */
514
515     opened = PARAM_NEED_ADP(bitmap);
516     adp = NULL;
517     if (opened) {
518         upath = path->u_name;
519         if ((of = of_findname(path))) {
520             adp = of->of_ad;
521             attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
522             attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
523         } else {
524             ad_init(&ad, vol->v_adouble);
525             adp = &ad;
526         }
527
528         if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
529              adp = NULL;
530         }
531         else {
532             /* FIXME 
533                we need to check if the file is open by another process.
534                it's slow so we only do it if we have to:
535                - bitmap is requested.
536                - we don't already have the answer!
537             */
538             if ((bitmap & (1 << FILPBIT_ATTR))) {
539                  if (!(attrbits & ATTRBIT_ROPEN)) {
540                      attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
541                      attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
542                  }
543                  if (!(attrbits & ATTRBIT_DOPEN)) {
544                      attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
545                      attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
546                  }
547             }
548         }
549     }
550     rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
551     if ( adp ) {
552         ad_close( adp, ADFLAGS_HF );
553     }
554 #ifdef DEBUG
555     LOG(log_info, logtype_afpd, "end getfilparams:");
556 #endif /* DEBUG */
557
558     return( rc );
559 }
560
561 /* ----------------------------- */
562 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
563 AFPObj      *obj;
564 char    *ibuf, *rbuf;
565 int             ibuflen, *rbuflen;
566 {
567     struct adouble      ad, *adp;
568     struct vol          *vol;
569     struct dir          *dir;
570     struct ofork        *of = NULL;
571     char                *path, *upath;
572     int                 creatf, did, openf, retvalue = AFP_OK;
573     u_int16_t           vid;
574     int                 ret;
575     struct path         *s_path;
576     
577 #ifdef DEBUG
578     LOG(log_info, logtype_afpd, "begin afp_createfile:");
579 #endif /* DEBUG */
580
581     *rbuflen = 0;
582     ibuf++;
583     creatf = (unsigned char) *ibuf++;
584
585     memcpy(&vid, ibuf, sizeof( vid ));
586     ibuf += sizeof( vid );
587
588     if (NULL == ( vol = getvolbyvid( vid )) ) {
589         return( AFPERR_PARAM );
590     }
591
592     if (vol->v_flags & AFPVOL_RO)
593         return AFPERR_VLOCK;
594
595     memcpy(&did, ibuf, sizeof( did));
596     ibuf += sizeof( did );
597
598     if (NULL == ( dir = dirlookup( vol, did )) ) {
599         return afp_errno;
600     }
601
602     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
603         return get_afp_errno(AFPERR_PARAM);
604     }
605
606     if ( *s_path->m_name == '\0' ) {
607         return( AFPERR_BADTYPE );
608     }
609
610     upath = s_path->u_name;
611     if (0 != (ret = check_name(vol, upath))) 
612        return  ret;
613     
614     /* if upath is deleted we already in trouble anyway */
615     if ((of = of_findname(s_path))) {
616         adp = of->of_ad;
617     } else {
618         ad_init(&ad, vol->v_adouble);
619         adp = &ad;
620     }
621     if ( creatf) {
622         /* on a hard create, fail if file exists and is open */
623         if (of)
624             return AFPERR_BUSY;
625         openf = O_RDWR|O_CREAT|O_TRUNC;
626     } else {
627         /* on a soft create, if the file is open then ad_open won't fail
628            because open syscall is not called
629         */
630         if (of) {
631                 return AFPERR_EXIST;
632         }
633         openf = O_RDWR|O_CREAT|O_EXCL;
634     }
635
636     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
637                   openf, 0666, adp) < 0 ) {
638         switch ( errno ) {
639         case EROFS:
640             return AFPERR_VLOCK;
641         case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
642             return ( AFPERR_NOOBJ );
643         case EEXIST :
644             return( AFPERR_EXIST );
645         case EACCES :
646             return( AFPERR_ACCESS );
647         default :
648             return( AFPERR_PARAM );
649         }
650     }
651     if ( ad_hfileno( adp ) == -1 ) {
652          /* on noadouble volumes, just creating the data fork is ok */
653          if (vol_noadouble(vol)) {
654              ad_close( adp, ADFLAGS_DF );
655              goto createfile_done;
656          }
657          /* FIXME with hard create on an existing file, we already
658           * corrupted the data file.
659           */
660          netatalk_unlink( upath );
661          ad_close( adp, ADFLAGS_DF );
662          return AFPERR_ACCESS;
663     }
664
665     path = s_path->m_name;
666     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
667     memcpy(ad_entry( adp, ADEID_NAME ), path,
668            ad_getentrylen( adp, ADEID_NAME ));
669     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
670     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
671
672 createfile_done:
673     curdir->offcnt++;
674
675 #ifdef DROPKLUDGE
676     if (vol->v_flags & AFPVOL_DROPBOX) {
677         retvalue = matchfile2dirperms(upath, vol, did);
678     }
679 #endif /* DROPKLUDGE */
680
681     setvoltime(obj, vol );
682
683 #ifdef DEBUG
684     LOG(log_info, logtype_afpd, "end afp_createfile");
685 #endif /* DEBUG */
686
687     return (retvalue);
688 }
689
690 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
691 AFPObj      *obj;
692 char    *ibuf, *rbuf;
693 int             ibuflen, *rbuflen;
694 {
695     struct vol  *vol;
696     struct dir  *dir;
697     struct path *s_path;
698     int         did, rc;
699     u_int16_t   vid, bitmap;
700
701 #ifdef DEBUG
702     LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
703 #endif /* DEBUG */
704
705     *rbuflen = 0;
706     ibuf += 2;
707
708     memcpy(&vid, ibuf, sizeof( vid ));
709     ibuf += sizeof( vid );
710     if (NULL == ( vol = getvolbyvid( vid )) ) {
711         return( AFPERR_PARAM );
712     }
713
714     if (vol->v_flags & AFPVOL_RO)
715         return AFPERR_VLOCK;
716
717     memcpy(&did, ibuf, sizeof( did ));
718     ibuf += sizeof( did );
719     if (NULL == ( dir = dirlookup( vol, did )) ) {
720         return afp_errno; /* was AFPERR_NOOBJ */
721     }
722
723     memcpy(&bitmap, ibuf, sizeof( bitmap ));
724     bitmap = ntohs( bitmap );
725     ibuf += sizeof( bitmap );
726
727     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
728         return get_afp_errno(AFPERR_PARAM);
729     }
730
731     if (path_isadir(s_path)) {
732         return( AFPERR_BADTYPE ); /* it's a directory */
733     }
734
735     if ( s_path->st_errno != 0 ) {
736         return( AFPERR_NOOBJ );
737     }
738
739     if ((u_long)ibuf & 1 ) {
740         ibuf++;
741     }
742
743     if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
744         setvoltime(obj, vol );
745     }
746
747 #ifdef DEBUG
748     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
749 #endif /* DEBUG */
750
751     return( rc );
752 }
753
754 /*
755  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
756  *
757 */
758 extern struct path Cur_Path;
759
760 int setfilparams(struct vol *vol,
761                  struct path *path, u_int16_t bitmap, char *buf )
762 {
763     struct adouble      ad, *adp;
764     struct ofork        *of;
765     struct extmap       *em;
766     int                 bit = 0, isad = 1, err = AFP_OK;
767     char                *upath;
768     u_char              achar, *fdType, xyy[4];
769     u_int16_t           ashort, bshort;
770     u_int32_t           aint;
771     struct utimbuf      ut;
772
773     int                 change_mdate = 0;
774     int                 change_parent_mdate = 0;
775     int                 newdate = 0;
776     struct timeval      tv;
777
778
779 #ifdef DEBUG
780     LOG(log_info, logtype_afpd, "begin setfilparams:");
781 #endif /* DEBUG */
782
783     upath = path->u_name;
784     if ((of = of_findname(path))) {
785         adp = of->of_ad;
786     } else {
787         ad_init(&ad, vol->v_adouble);
788         adp = &ad;
789     }
790
791     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
792         return AFPERR_ACCESS;
793     }
794
795     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
796                  O_RDWR|O_CREAT, 0666, adp) < 0) {
797         /* for some things, we don't need an adouble header */
798         if (bitmap & ~(1<<FILPBIT_MDATE)) {
799             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
800         }
801         isad = 0;
802     } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
803         ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
804         memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
805                ad_getentrylen( adp, ADEID_NAME ));
806     }
807
808     while ( bitmap != 0 ) {
809         while (( bitmap & 1 ) == 0 ) {
810             bitmap = bitmap>>1;
811             bit++;
812         }
813
814         switch(  bit ) {
815         case FILPBIT_ATTR :
816             change_mdate = 1;
817             memcpy(&ashort, buf, sizeof( ashort ));
818             ad_getattr(adp, &bshort);
819             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
820                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
821             } else {
822                 bshort &= ~ashort;
823             }
824             if ((ashort & htons(ATTRBIT_INVISIBLE)))
825                 change_parent_mdate = 1;
826             ad_setattr(adp, bshort);
827             buf += sizeof( ashort );
828             break;
829
830         case FILPBIT_CDATE :
831             change_mdate = 1;
832             memcpy(&aint, buf, sizeof(aint));
833             ad_setdate(adp, AD_DATE_CREATE, aint);
834             buf += sizeof( aint );
835             break;
836
837         case FILPBIT_MDATE :
838             memcpy(&newdate, buf, sizeof( newdate ));
839             buf += sizeof( newdate );
840             break;
841
842         case FILPBIT_BDATE :
843             change_mdate = 1;
844             memcpy(&aint, buf, sizeof(aint));
845             ad_setdate(adp, AD_DATE_BACKUP, aint);
846             buf += sizeof( aint );
847             break;
848
849         case FILPBIT_FINFO :
850             change_mdate = 1;
851
852             if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
853                     && ( 
854                      ((em = getextmap( path->m_name )) &&
855                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
856                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
857                      || ((em = getdefextmap()) &&
858                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
859                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
860             )) {
861                 memcpy(buf, ufinderi, 8 );
862             }
863
864             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
865             buf += 32;
866             break;
867
868         case FILPBIT_UNIXPR :
869             /* Skip the UIG/GID, no way to set them from OSX clients */
870             buf += sizeof( aint );
871             buf += sizeof( aint );
872
873             change_mdate = 1;
874             change_parent_mdate = 1;
875             memcpy( &aint, buf, sizeof( aint ));
876             buf += sizeof( aint );
877             aint = ntohl (aint);
878
879             setfilemode(path, aint);
880             break;
881             /* Client needs to set the ProDOS file info for this file.
882                Use a defined string for TEXT to support crlf
883                translations and convert all else into pXYY per Inside
884                Appletalk.  Always set the creator as "pdos".  Changes
885                from original by Marsha Jackson. */
886         case FILPBIT_PDINFO :
887             if (afp_version < 30) { /* else it's UTF8 name */
888                 achar = *buf;
889                 buf += 2;
890                 /* Keep special case to support crlf translations */
891                 if ((unsigned int) achar == 0x04) {
892                     fdType = (u_char *)"TEXT";
893                     buf += 2;
894                 } else {
895                     xyy[0] = ( u_char ) 'p';
896                     xyy[1] = achar;
897                     xyy[3] = *buf++;
898                     xyy[2] = *buf++;
899                     fdType = xyy;
900                 }
901                 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
902                 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
903                 break;
904             }
905             /* fallthrough */
906         default :
907             err = AFPERR_BITMAP;
908             goto setfilparam_done;
909         }
910
911         bitmap = bitmap>>1;
912         bit++;
913     }
914
915 setfilparam_done:
916     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
917        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
918     }
919     if (newdate) {
920        if (isad)
921           ad_setdate(adp, AD_DATE_MODIFY, newdate);
922        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
923        utime(upath, &ut);
924     }
925
926     if (isad) {
927         ad_flush( adp, ADFLAGS_HF );
928         ad_close( adp, ADFLAGS_HF );
929
930     }
931
932     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
933         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
934         bitmap = 1<<FILPBIT_MDATE;
935         setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
936     }
937
938 #ifdef DEBUG
939     LOG(log_info, logtype_afpd, "end setfilparams:");
940 #endif /* DEBUG */
941     return err;
942 }
943
944 /*
945  * renamefile and copyfile take the old and new unix pathnames
946  * and the new mac name.
947  *
948  * src         the source path 
949  * dst         the dest filename in current dir
950  * newname     the dest mac name
951  * adp         adouble struct of src file, if open, or & zeroed one
952  *
953  */
954 int renamefile(src, dst, newname, noadouble, adp )
955 char    *src, *dst, *newname;
956 const int         noadouble;
957 struct adouble    *adp;
958 {
959     char        adsrc[ MAXPATHLEN + 1];
960     int         len;
961     int         rc;
962
963 #ifdef DEBUG
964     LOG(log_info, logtype_afpd, "begin renamefile:");
965 #endif /* DEBUG */
966
967     if ( unix_rename( src, dst ) < 0 ) {
968         switch ( errno ) {
969         case ENOENT :
970             return( AFPERR_NOOBJ );
971         case EPERM:
972         case EACCES :
973             return( AFPERR_ACCESS );
974         case EROFS:
975             return AFPERR_VLOCK;
976         case EXDEV :                    /* Cross device move -- try copy */
977            /* NOTE: with open file it's an error because after the copy we will 
978             * get two files, it's fixable for our process (eg reopen the new file, get the
979             * locks, and so on. But it doesn't solve the case with a second process
980             */
981             if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
982                 /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
983                 return AFPERR_OLOCK; /* little lie */
984             }
985             if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
986                 /* on error copyfile delete dest */
987                 return( rc );
988             }
989             return deletefile(NULL, src, 0);
990         default :
991             return( AFPERR_PARAM );
992         }
993     }
994
995     strcpy( adsrc, ad_path( src, 0 ));
996
997     if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
998         struct stat st;
999         int err;
1000         
1001         err = errno;        
1002         if (errno == ENOENT) {
1003             struct adouble    ad;
1004
1005             if (stat(adsrc, &st)) /* source has no ressource fork, */
1006                 return AFP_OK;
1007             
1008             /* We are here  because :
1009              * -there's no dest folder. 
1010              * -there's no .AppleDouble in the dest folder.
1011              * if we use the struct adouble passed in parameter it will not
1012              * create .AppleDouble if the file is already opened, so we
1013              * use a diff one, it's not a pb,ie it's not the same file, yet.
1014              */
1015             ad_init(&ad, AD_VERSION); /* FIXME */
1016             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1017                 ad_close(&ad, ADFLAGS_HF);
1018                 if (!unix_rename( adsrc, ad_path( dst, 0 )) ) 
1019                    err = 0;
1020                 else 
1021                    err = errno;
1022             }
1023             else { /* it's something else, bail out */
1024                 err = errno;
1025             }
1026         }
1027         /* try to undo the data fork rename,
1028          * we know we are on the same device 
1029         */
1030         if (err) {
1031             unix_rename( dst, src ); 
1032             /* return the first error */
1033             switch ( err) {
1034             case ENOENT :
1035                 return AFPERR_NOOBJ;
1036             case EPERM:
1037             case EACCES :
1038                 return AFPERR_ACCESS ;
1039             case EROFS:
1040                 return AFPERR_VLOCK;
1041             default :
1042                 return AFPERR_PARAM ;
1043             }
1044         }
1045     }
1046
1047     /* don't care if we can't open the newly renamed ressource fork
1048      */
1049     if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1050         len = strlen( newname );
1051         ad_setentrylen( adp, ADEID_NAME, len );
1052         memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1053         ad_flush( adp, ADFLAGS_HF );
1054         ad_close( adp, ADFLAGS_HF );
1055     }
1056 #ifdef DEBUG
1057     LOG(log_info, logtype_afpd, "end renamefile:");
1058 #endif /* DEBUG */
1059
1060     return( AFP_OK );
1061 }
1062
1063 int copy_path_name(char *newname, char *ibuf)
1064 {
1065 char        type = *ibuf;
1066 size_t      plen = 0;
1067 u_int16_t   len16;
1068 u_int32_t   hint;
1069
1070     if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1071         return -1;
1072     }
1073     ibuf++;
1074     switch (type) {
1075     case 2:
1076         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1077             strncpy( newname, ibuf, plen );
1078             newname[ plen ] = '\0';
1079             if (strlen(newname) != plen) {
1080                 /* there's \0 in newname, e.g. it's a pathname not
1081                  * only a filename. 
1082                 */
1083                 return -1;
1084             }
1085         }
1086         break;
1087     case 3:
1088         memcpy(&hint, ibuf, sizeof(hint));
1089         ibuf += sizeof(hint);
1090            
1091         memcpy(&len16, ibuf, sizeof(len16));
1092         ibuf += sizeof(len16);
1093         plen = ntohs(len16);
1094         
1095         if (plen) {
1096             if (plen > AFPOBJ_TMPSIZ) {
1097                 return -1;
1098             }
1099             strncpy( newname, ibuf, plen );
1100             newname[ plen ] = '\0';
1101             if (strlen(newname) != plen) {
1102                 return -1;
1103             }
1104         }
1105         break;
1106     }
1107     return plen;
1108 }
1109
1110 /* -----------------------------------
1111 */
1112 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1113 AFPObj      *obj;
1114 char    *ibuf, *rbuf;
1115 int             ibuflen, *rbuflen;
1116 {
1117     struct vol  *vol;
1118     struct dir  *dir;
1119     char        *newname, *p, *upath;
1120     struct path *s_path;
1121     u_int32_t   sdid, ddid;
1122     int         err, retvalue = AFP_OK;
1123     u_int16_t   svid, dvid;
1124
1125 #ifdef DEBUG
1126     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1127 #endif /* DEBUG */
1128
1129     *rbuflen = 0;
1130     ibuf += 2;
1131
1132     memcpy(&svid, ibuf, sizeof( svid ));
1133     ibuf += sizeof( svid );
1134     if (NULL == ( vol = getvolbyvid( svid )) ) {
1135         return( AFPERR_PARAM );
1136     }
1137
1138     memcpy(&sdid, ibuf, sizeof( sdid ));
1139     ibuf += sizeof( sdid );
1140     if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1141         return afp_errno;
1142     }
1143
1144     memcpy(&dvid, ibuf, sizeof( dvid ));
1145     ibuf += sizeof( dvid );
1146     memcpy(&ddid, ibuf, sizeof( ddid ));
1147     ibuf += sizeof( ddid );
1148
1149     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1150         return get_afp_errno(AFPERR_PARAM);
1151     }
1152     if ( path_isadir(s_path) ) {
1153         return( AFPERR_BADTYPE );
1154     }
1155
1156     /* don't allow copies when the file is open.
1157      * XXX: the spec only calls for read/deny write access.
1158      *      however, copyfile doesn't have any of that info,
1159      *      and locks need to stay coherent. as a result,
1160      *      we just balk if the file is opened already. */
1161
1162     newname = obj->newtmp;
1163     strcpy( newname, s_path->m_name );
1164
1165     if (of_findname(s_path))
1166         return AFPERR_DENYCONF;
1167
1168     p = ctoupath( vol, curdir, newname );
1169     if (!p) {
1170         return AFPERR_PARAM;
1171     
1172     }
1173 #ifdef FORCE_UIDGID
1174     /* FIXME svid != dvid && dvid's user can't read svid */
1175 #endif
1176     if (NULL == ( vol = getvolbyvid( dvid )) ) {
1177         return( AFPERR_PARAM );
1178     }
1179
1180     if (vol->v_flags & AFPVOL_RO)
1181         return AFPERR_VLOCK;
1182
1183     if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1184         return afp_errno;
1185     }
1186
1187     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1188         return get_afp_errno(AFPERR_NOOBJ); 
1189     }
1190     if ( *s_path->m_name != '\0' ) {
1191 #if 0
1192         return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1193 #endif        
1194         path_error(s_path, AFPERR_PARAM);
1195     }
1196
1197     /* one of the handful of places that knows about the path type */
1198     if (copy_path_name(newname, ibuf) < 0) {
1199         return( AFPERR_PARAM );
1200     }
1201     /* newname is always only a filename so curdir *is* its
1202      * parent folder
1203     */
1204     if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))) {
1205         return( AFPERR_PARAM );
1206     }
1207     if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1208         return err;
1209     }
1210     curdir->offcnt++;
1211
1212 #ifdef DROPKLUDGE
1213     if (vol->v_flags & AFPVOL_DROPBOX) {
1214         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1215     }
1216 #endif /* DROPKLUDGE */
1217
1218     setvoltime(obj, vol );
1219
1220 #ifdef DEBUG
1221     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1222 #endif /* DEBUG */
1223
1224     return( retvalue );
1225 }
1226
1227
1228 static __inline__ int copy_all(const int dfd, const void *buf,
1229                                size_t buflen)
1230 {
1231     ssize_t cc;
1232
1233 #ifdef DEBUG
1234     LOG(log_info, logtype_afpd, "begin copy_all:");
1235 #endif /* DEBUG */
1236
1237     while (buflen > 0) {
1238         if ((cc = write(dfd, buf, buflen)) < 0) {
1239             switch (errno) {
1240             case EINTR:
1241                 continue;
1242             case EDQUOT:
1243             case EFBIG:
1244             case ENOSPC:
1245                 return AFPERR_DFULL;
1246             case EROFS:
1247                 return AFPERR_VLOCK;
1248             default:
1249                 return AFPERR_PARAM;
1250             }
1251         }
1252         buflen -= cc;
1253     }
1254
1255 #ifdef DEBUG
1256     LOG(log_info, logtype_afpd, "end copy_all:");
1257 #endif /* DEBUG */
1258
1259     return AFP_OK;
1260 }
1261
1262 /* -------------------------- */
1263 static int copy_fd(int dfd, int sfd)
1264 {
1265     ssize_t cc;
1266     int     err = AFP_OK;
1267     char    filebuf[8192];
1268     
1269 #ifdef SENDFILE_FLAVOR_LINUX
1270     off_t   offset = 0;
1271     size_t  size;
1272     struct stat         st;
1273     #define BUF 128*1024*1024
1274
1275     if (fstat(sfd, &st) == 0) {
1276         
1277         while (1) {
1278             if ( offset >= st.st_size) {
1279                return AFP_OK;
1280             }
1281             size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1282             if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1283                 switch (errno) {
1284                 case ENOSYS:
1285                 case EINVAL:  /* there's no guarantee that all fs support sendfile */
1286                     goto no_sendfile;
1287                 case EDQUOT:
1288                 case EFBIG:
1289                 case ENOSPC:
1290                     return AFPERR_DFULL;
1291                 case EROFS:
1292                     return AFPERR_VLOCK;
1293                 default:
1294                     return AFPERR_PARAM;
1295                 }
1296             }
1297         }
1298     }
1299     no_sendfile:
1300     lseek(sfd, offset, SEEK_SET);
1301 #endif 
1302
1303     while (1) {
1304         if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1305             if (errno == EINTR)
1306                 continue;
1307             err = AFPERR_PARAM;
1308             break;
1309         }
1310
1311         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1312             break;
1313     }
1314     return err;
1315 }
1316
1317 /* ----------------------------------
1318  * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1319  * because we are doing it elsewhere.
1320  */
1321 int copyfile(src, dst, newname, noadouble )
1322 char    *src, *dst, *newname;
1323 const int   noadouble;
1324 {
1325     struct adouble      ads, add;
1326     int                 len, err = AFP_OK;
1327     int                 adflags;
1328     struct stat         st;
1329     
1330 #ifdef DEBUG
1331     LOG(log_info, logtype_afpd, "begin copyfile:");
1332 #endif /* DEBUG */
1333
1334     ad_init(&ads, 0); /* OK */
1335     ad_init(&add, 0); /* FIXME */
1336     adflags = ADFLAGS_DF;
1337     if (newname) {
1338         adflags |= ADFLAGS_HF;
1339     }
1340
1341     if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1342         switch ( errno ) {
1343         case ENOENT :
1344             return( AFPERR_NOOBJ );
1345         case EACCES :
1346             return( AFPERR_ACCESS );
1347         default :
1348             return( AFPERR_PARAM );
1349         }
1350     }
1351     if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1352         ad_close( &ads, adflags );
1353         if (EEXIST != (err = errno)) {
1354             deletefile(NULL, dst, 0);
1355         }
1356         switch ( err ) {
1357         case EEXIST :
1358             return AFPERR_EXIST;
1359         case ENOENT :
1360             return( AFPERR_NOOBJ );
1361         case EACCES :
1362             return( AFPERR_ACCESS );
1363         case EROFS:
1364             return AFPERR_VLOCK;
1365         default :
1366             return( AFPERR_PARAM );
1367         }
1368     }
1369     if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1370         /* copy the data fork */
1371         err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1372     }
1373
1374     /* Now, reopen destination file */
1375     err = AFP_OK;
1376     if (ad_close( &add, adflags ) <0) {
1377         deletefile(NULL, dst, 0);
1378         return AFPERR_PARAM;  /* FIXME */
1379     } else {
1380         ad_init(&add, 0);
1381         if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1382             ad_close( &ads, adflags );
1383             deletefile(NULL, dst, 0);
1384             switch ( err ) {
1385             case ENOENT :
1386                 return( AFPERR_NOOBJ );
1387             case EACCES :
1388                 return( AFPERR_ACCESS );
1389             case EROFS:
1390                 return AFPERR_VLOCK;
1391             default :
1392                 return( AFPERR_PARAM );
1393             }
1394         }
1395     }
1396
1397     if (newname) {
1398         len = strlen( newname );
1399         ad_setentrylen( &add, ADEID_NAME, len );
1400         memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1401     }
1402
1403     ad_close( &ads, adflags );
1404     ad_flush( &add, adflags );
1405     if (ad_close( &add, adflags ) <0) {
1406        err = errno;
1407     }
1408     if (err != AFP_OK) {
1409         deletefile(NULL, dst, 0);
1410         switch ( err ) {
1411         case ENOENT :
1412             return( AFPERR_NOOBJ );
1413         case EACCES :
1414             return( AFPERR_ACCESS );
1415         default :
1416             return( AFPERR_PARAM );
1417         }
1418     }
1419
1420     /* set dest modification date to src date */
1421     if (!stat(src, &st)) {
1422         struct utimbuf  ut;
1423
1424         ut.actime = ut.modtime = st.st_mtime;
1425         utime(dst, &ut);
1426     }
1427
1428 #ifdef DEBUG
1429     LOG(log_info, logtype_afpd, "end copyfile:");
1430 #endif /* DEBUG */
1431
1432     return( AFP_OK );
1433 }
1434
1435
1436 /* -----------------------------------
1437    vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1438    checkAttrib:   1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1439
1440    when deletefile is called we don't have lock on it, file is closed (for us)
1441    untrue if called by renamefile
1442    
1443    ad_open always try to open file RDWR first and ad_lock takes care of
1444    WRITE lock on read only file.
1445 */
1446 int deletefile( vol, file, checkAttrib )
1447 struct vol      *vol;
1448 char            *file;
1449 int         checkAttrib;
1450 {
1451     struct adouble      ad;
1452     int                 adflags, err = AFP_OK;
1453
1454 #ifdef DEBUG
1455     LOG(log_info, logtype_afpd, "begin deletefile:");
1456 #endif /* DEBUG */
1457
1458     /* try to open both forks at once */
1459     adflags = ADFLAGS_DF|ADFLAGS_HF;
1460     while(1) {
1461         ad_init(&ad, 0);  /* OK */
1462         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1463             switch (errno) {
1464             case ENOENT:
1465                 if (adflags == ADFLAGS_DF)
1466                     return AFPERR_NOOBJ;
1467                    
1468                 /* that failed. now try to open just the data fork */
1469                 adflags = ADFLAGS_DF;
1470                 continue;
1471
1472             case EACCES:
1473                 return AFPERR_ACCESS;
1474             case EROFS:
1475                 return AFPERR_VLOCK;
1476             default:
1477                 return( AFPERR_PARAM );
1478             }
1479         }
1480         break;  /* from the while */
1481     }
1482     /*
1483      * Does kFPDeleteInhibitBit (bit 8) set?
1484      */
1485     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1486         u_int16_t   bshort;
1487
1488         ad_getattr(&ad, &bshort);
1489         if ((bshort & htons(ATTRBIT_NODELETE))) {
1490             ad_close( &ad, adflags );
1491             return(AFPERR_OLOCK);
1492         }
1493     }
1494     
1495     if ((adflags & ADFLAGS_HF) ) {
1496         /* FIXME we have a pb here because we want to know if a file is open 
1497          * there's a 'priority inversion' if you can't open the ressource fork RW
1498          * you can delete it if it's open because you can't get a write lock.
1499          * 
1500          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1501          * metadatas
1502          *
1503          * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1504          */
1505         if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1506             ad_close( &ad, adflags );
1507             return( AFPERR_BUSY );
1508         }
1509     }
1510
1511     if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1512         err = AFPERR_BUSY;
1513     }
1514     else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1515              !(err = netatalk_unlink( file )) ) {
1516         cnid_t id;
1517         if (vol && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
1518         {
1519             cnid_delete(vol->v_cdb, id);
1520         }
1521
1522     }
1523     ad_close( &ad, adflags );  /* ad_close removes locks if any */
1524
1525 #ifdef DEBUG
1526     LOG(log_info, logtype_afpd, "end deletefile:");
1527 #endif /* DEBUG */
1528
1529     return err;
1530 }
1531
1532 /* ------------------------------------ */
1533 /* return a file id */
1534 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1535 AFPObj      *obj;
1536 char    *ibuf, *rbuf;
1537 int             ibuflen, *rbuflen;
1538 {
1539     struct stat         *st;
1540     struct vol          *vol;
1541     struct dir          *dir;
1542     char                *upath;
1543     int                 len;
1544     cnid_t              did, id;
1545     u_short             vid;
1546     struct path         *s_path;
1547
1548 #ifdef DEBUG
1549     LOG(log_info, logtype_afpd, "begin afp_createid:");
1550 #endif /* DEBUG */
1551
1552     *rbuflen = 0;
1553
1554     ibuf += 2;
1555
1556     memcpy(&vid, ibuf, sizeof(vid));
1557     ibuf += sizeof(vid);
1558
1559     if (NULL == ( vol = getvolbyvid( vid )) ) {
1560         return( AFPERR_PARAM);
1561     }
1562
1563     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1564         return AFPERR_NOOP;
1565     }
1566
1567     if (vol->v_flags & AFPVOL_RO)
1568         return AFPERR_VLOCK;
1569
1570     memcpy(&did, ibuf, sizeof( did ));
1571     ibuf += sizeof(did);
1572
1573     if (NULL == ( dir = dirlookup( vol, did )) ) {
1574         return afp_errno; /* was AFPERR_PARAM */
1575     }
1576
1577     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1578         return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1579     }
1580
1581     if ( path_isadir(s_path) ) {
1582         return( AFPERR_BADTYPE );
1583     }
1584
1585     upath = s_path->u_name;
1586     switch (s_path->st_errno) {
1587         case 0:
1588              break; /* success */
1589         case EPERM:
1590         case EACCES:
1591             return AFPERR_ACCESS;
1592         case ENOENT:
1593             return AFPERR_NOOBJ;
1594         default:
1595             return AFPERR_PARAM;
1596     }
1597     st = &s_path->st;
1598     if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1599         memcpy(rbuf, &id, sizeof(id));
1600         *rbuflen = sizeof(id);
1601         return AFPERR_EXISTID;
1602     }
1603
1604     if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1605         memcpy(rbuf, &id, sizeof(id));
1606         *rbuflen = sizeof(id);
1607         return AFP_OK;
1608     }
1609
1610 #ifdef DEBUG
1611     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1612 #endif /* DEBUG */
1613     return afp_errno;
1614 }
1615
1616 static int
1617 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1618 {
1619     DIR             *dp;
1620     struct dirent   *de;
1621     int             ret;
1622     struct stat     st;
1623     cnid_t          aint;
1624     struct adouble  ad;
1625         
1626
1627     if (vol->v_cdb == NULL) {
1628         return -1;
1629     }
1630     if (NULL == ( dp = opendir( name)) ) {
1631         return -1;
1632     }
1633     ret = 0;
1634     for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1635         if (NULL == check_dirent(vol, de->d_name))
1636             continue;
1637
1638         if ( stat(de->d_name, &st)<0 )
1639             continue;
1640         
1641         /* update or add to cnid */
1642         aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1643
1644 #if AD_VERSION > AD_VERSION1
1645         if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
1646             ad_init(&ad, 0);  /* OK */
1647             if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
1648                 continue;
1649             }
1650             else {
1651                 ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
1652                 ad_flush(&ad, ADFLAGS_HF);
1653                 ad_close(&ad, ADFLAGS_HF);
1654            }
1655         }
1656 #endif /* AD_VERSION > AD_VERSION1 */
1657
1658         ret++;
1659     }
1660     closedir(dp);
1661     return ret;
1662 }
1663
1664     
1665 /* ------------------------------
1666    resolve a file id */
1667 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1668 AFPObj      *obj;
1669 char    *ibuf, *rbuf;
1670 int             ibuflen, *rbuflen;
1671 {
1672     struct vol          *vol;
1673     struct dir          *dir;
1674     char                *upath;
1675     struct path         path;
1676     int                 err, buflen, retry=0;
1677     cnid_t              id, cnid;
1678     u_int16_t           vid, bitmap;
1679
1680     static char buffer[12 + MAXPATHLEN + 1];
1681     int len = 12 + MAXPATHLEN + 1;
1682
1683 #ifdef DEBUG
1684     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1685 #endif /* DEBUG */
1686
1687     *rbuflen = 0;
1688     ibuf += 2;
1689
1690     memcpy(&vid, ibuf, sizeof(vid));
1691     ibuf += sizeof(vid);
1692
1693     if (NULL == ( vol = getvolbyvid( vid )) ) {
1694         return( AFPERR_PARAM);
1695     }
1696
1697     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1698         return AFPERR_NOOP;
1699     }
1700
1701     memcpy(&id, ibuf, sizeof( id ));
1702     ibuf += sizeof(id);
1703     cnid = id;
1704
1705 retry:
1706     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1707         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1708     }
1709
1710     if (NULL == ( dir = dirlookup( vol, id )) ) {
1711         return AFPERR_NOID; /* idem AFPERR_PARAM */
1712     }
1713     path.u_name = upath;
1714     if (movecwd(vol, dir) < 0) {
1715         switch (errno) {
1716         case EACCES:
1717         case EPERM:
1718             return AFPERR_ACCESS;
1719         case ENOENT:
1720             return AFPERR_NOID;
1721         default:
1722             return AFPERR_PARAM;
1723         }
1724     }
1725
1726     if ( of_stat(&path) < 0 ) {
1727         if ( errno == ENOENT && !retry) {
1728             /* cnid db is out of sync, reenumerate the directory and updated ids */
1729             reenumerate_id(vol, ".", id);
1730             id = cnid;
1731             retry = 1;
1732             goto retry;
1733         }
1734         switch (errno) {
1735         case EACCES:
1736         case EPERM:
1737             return AFPERR_ACCESS;
1738         case ENOENT:
1739             return AFPERR_NOID;
1740         default:
1741             return AFPERR_PARAM;
1742         }
1743     }
1744
1745     /* directories are bad */
1746     if (S_ISDIR(path.st.st_mode))
1747         return AFPERR_BADTYPE;
1748
1749     memcpy(&bitmap, ibuf, sizeof(bitmap));
1750     bitmap = ntohs( bitmap );
1751     if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1752         return AFPERR_NOID;
1753     }
1754     if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 
1755                             rbuf + sizeof(bitmap), &buflen))) {
1756         return err;
1757     }
1758     *rbuflen = buflen + sizeof(bitmap);
1759     memcpy(rbuf, ibuf, sizeof(bitmap));
1760
1761 #ifdef DEBUG
1762     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1763 #endif /* DEBUG */
1764
1765     return AFP_OK;
1766 }
1767
1768 /* ------------------------------ */
1769 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1770 AFPObj      *obj;
1771 char    *ibuf, *rbuf;
1772 int             ibuflen, *rbuflen;
1773 {
1774     struct stat         st;
1775     struct vol          *vol;
1776     struct dir          *dir;
1777     char                *upath;
1778     int                 err;
1779     cnid_t              id;
1780     cnid_t              fileid;
1781     u_short             vid;
1782     static char buffer[12 + MAXPATHLEN + 1];
1783     int len = 12 + MAXPATHLEN + 1;
1784
1785 #ifdef DEBUG
1786     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1787 #endif /* DEBUG */
1788
1789     *rbuflen = 0;
1790     ibuf += 2;
1791
1792     memcpy(&vid, ibuf, sizeof(vid));
1793     ibuf += sizeof(vid);
1794
1795     if (NULL == ( vol = getvolbyvid( vid )) ) {
1796         return( AFPERR_PARAM);
1797     }
1798
1799     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1800         return AFPERR_NOOP;
1801     }
1802
1803     if (vol->v_flags & AFPVOL_RO)
1804         return AFPERR_VLOCK;
1805
1806     memcpy(&id, ibuf, sizeof( id ));
1807     ibuf += sizeof(id);
1808     fileid = id;
1809
1810     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1811         return AFPERR_NOID;
1812     }
1813
1814     if (NULL == ( dir = dirlookup( vol, id )) ) {
1815         return( AFPERR_PARAM );
1816     }
1817
1818     err = AFP_OK;
1819     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1820         switch (errno) {
1821         case EACCES:
1822         case EPERM:
1823             return AFPERR_ACCESS;
1824         case ENOENT:
1825             /* still try to delete the id */
1826             err = AFPERR_NOOBJ;
1827             break;
1828         default:
1829             return AFPERR_PARAM;
1830         }
1831     }
1832     else if (S_ISDIR(st.st_mode)) /* directories are bad */
1833         return AFPERR_BADTYPE;
1834
1835     if (cnid_delete(vol->v_cdb, fileid)) {
1836         switch (errno) {
1837         case EROFS:
1838             return AFPERR_VLOCK;
1839         case EPERM:
1840         case EACCES:
1841             return AFPERR_ACCESS;
1842         default:
1843             return AFPERR_PARAM;
1844         }
1845     }
1846
1847 #ifdef DEBUG
1848     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1849 #endif /* DEBUG */
1850
1851     return err;
1852 }
1853
1854 #define APPLETEMP ".AppleTempXXXXXX"
1855
1856 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1857 AFPObj      *obj;
1858 char    *ibuf, *rbuf;
1859 int             ibuflen, *rbuflen;
1860 {
1861     struct stat         srcst, destst;
1862     struct vol          *vol;
1863     struct dir          *dir, *sdir;
1864     char                *spath, temp[17], *p;
1865     char                *supath, *upath;
1866     struct path         *path;
1867     int                 err;
1868     struct adouble      ads;
1869     struct adouble      add;
1870     struct adouble      *adsp;
1871     struct adouble      *addp;
1872     struct ofork        *s_of;
1873     struct ofork        *d_of;
1874     int                 crossdev;
1875     
1876     int                 slen, dlen;
1877     u_int32_t           sid, did;
1878     u_int16_t           vid;
1879
1880 #ifdef DEBUG
1881     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1882 #endif /* DEBUG */
1883
1884     *rbuflen = 0;
1885     ibuf += 2;
1886
1887     memcpy(&vid, ibuf, sizeof(vid));
1888     ibuf += sizeof(vid);
1889
1890     if (NULL == ( vol = getvolbyvid( vid )) ) {
1891         return( AFPERR_PARAM);
1892     }
1893
1894     if (vol->v_flags & AFPVOL_RO)
1895         return AFPERR_VLOCK;
1896
1897     /* source and destination dids */
1898     memcpy(&sid, ibuf, sizeof(sid));
1899     ibuf += sizeof(sid);
1900     memcpy(&did, ibuf, sizeof(did));
1901     ibuf += sizeof(did);
1902
1903     /* source file */
1904     if (NULL == (dir = dirlookup( vol, sid )) ) {
1905         return afp_errno; /* was AFPERR_PARAM */
1906     }
1907
1908     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1909         return get_afp_errno(AFPERR_NOOBJ); 
1910     }
1911
1912     if ( path_isadir(path) ) {
1913         return( AFPERR_BADTYPE );   /* it's a dir */
1914     }
1915
1916     upath = path->u_name;
1917     switch (path->st_errno) {
1918         case 0:
1919              break;
1920         case ENOENT:
1921             return AFPERR_NOID;
1922         case EPERM:
1923         case EACCES:
1924             return AFPERR_ACCESS;
1925         default:
1926             return AFPERR_PARAM;
1927     }
1928     ad_init(&ads, vol->v_adouble);
1929     adsp = &ads;
1930     if ((s_of = of_findname(path))) {
1931             /* reuse struct adouble so it won't break locks */
1932             adsp = s_of->of_ad;
1933     }
1934     memcpy(&srcst, &path->st, sizeof(struct stat));
1935     /* save some stuff */
1936     sdir = curdir;
1937     spath = obj->oldtmp;
1938     supath = obj->newtmp;
1939     strcpy(spath, path->m_name);
1940     strcpy(supath, upath); /* this is for the cnid changing */
1941     p = absupath( vol, sdir, upath);
1942     if (!p) {
1943         /* pathname too long */
1944         return AFPERR_PARAM ;
1945     }
1946
1947     /* look for the source cnid. if it doesn't exist, don't worry about
1948      * it. */
1949     sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1950
1951     if (NULL == ( dir = dirlookup( vol, did )) ) {
1952         return afp_errno; /* was AFPERR_PARAM */
1953     }
1954
1955     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1956         return get_afp_errno(AFPERR_NOOBJ); 
1957     }
1958
1959     if ( path_isadir(path) ) {
1960         return( AFPERR_BADTYPE );
1961     }
1962
1963     /* FPExchangeFiles is the only call that can return the SameObj
1964      * error */
1965     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1966         return AFPERR_SAMEOBJ;
1967
1968     switch (path->st_errno) {
1969         case 0:
1970              break;
1971         case ENOENT:
1972             return AFPERR_NOID;
1973         case EPERM:
1974         case EACCES:
1975             return AFPERR_ACCESS;
1976         default:
1977             return AFPERR_PARAM;
1978     }
1979     ad_init(&add, vol->v_adouble);
1980     addp = &add;
1981     if ((d_of = of_findname( path))) {
1982             /* reuse struct adouble so it won't break locks */
1983             addp = d_of->of_ad;
1984     }
1985     memcpy(&destst, &path->st, sizeof(struct stat));
1986
1987     /* they are not on the same device and at least one is open
1988     */
1989     crossdev = (srcst.st_dev != destst.st_dev);
1990     if ((d_of || s_of)  && crossdev)
1991         return AFPERR_MISC;
1992     
1993     upath = path->u_name;
1994     /* look for destination id. */
1995     did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
1996
1997     /* construct a temp name.
1998      * NOTE: the temp file will be in the dest file's directory. it
1999      * will also be inaccessible from AFP. */
2000     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2001     if (!mktemp(temp))
2002         return AFPERR_MISC;
2003
2004     /* now, quickly rename the file. we error if we can't. */
2005     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
2006         goto err_exchangefile;
2007     of_rename(vol, s_of, sdir, spath, curdir, temp);
2008
2009     /* rename destination to source */
2010     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
2011         goto err_src_to_tmp;
2012     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2013
2014     /* rename temp to destination */
2015     if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
2016         goto err_dest_to_src;
2017     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2018
2019     /* id's need switching. src -> dest and dest -> src. 
2020      * we need to re-stat() if it was a cross device copy.
2021     */
2022     if (sid) {
2023         cnid_delete(vol->v_cdb, sid);
2024     }
2025     if (did) {
2026         cnid_delete(vol->v_cdb, did);
2027     }
2028     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
2029                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2030        ||
2031        (sid && ( (crossdev && stat(p, &destst) < 0) ||
2032                 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2033     ) {
2034         switch (errno) {
2035         case EPERM:
2036         case EACCES:
2037             err = AFPERR_ACCESS;
2038             break;
2039         default:
2040             err = AFPERR_PARAM;
2041         }
2042         goto err_temp_to_dest;
2043     }
2044
2045 #ifdef DEBUG
2046     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2047 #endif /* DEBUG */
2048
2049     return AFP_OK;
2050
2051
2052     /* all this stuff is so that we can unwind a failed operation
2053      * properly. */
2054 err_temp_to_dest:
2055     /* rename dest to temp */
2056     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
2057     of_rename(vol, s_of, curdir, upath, curdir, temp);
2058
2059 err_dest_to_src:
2060     /* rename source back to dest */
2061     renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
2062     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2063
2064 err_src_to_tmp:
2065     /* rename temp back to source */
2066     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
2067     of_rename(vol, s_of, curdir, temp, sdir, spath);
2068
2069 err_exchangefile:
2070     return err;
2071 }