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