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