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