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