2 * $Id: file.c,v 1.92.2.2.2.3 2003-09-28 13:58:57 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
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 */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
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"
61 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
62 * field bytes subfield bytes
65 * ioFlFndrInfo 16 -> type 4 type field
66 * creator 4 creator field
67 * flags 2 finder flags:
69 * location 4 location in window
70 * folder 2 window that contains file
72 * ioFlXFndrInfo 16 -> iconID 2 icon id
74 * script 1 script system
76 * commentID 2 comment id
77 * putawayID 4 home directory id
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
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)
93 if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
94 memcpy(data, ad_finder, 32);
97 memcpy(data, ufinderi, 32);
100 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
101 && (em = getextmap( mpath ))
103 memcpy(data, em->em_type, sizeof( em->em_type ));
104 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
109 /* ---------------------
111 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
116 aint = strlen( name );
120 if (utf8_encoding()) {
121 /* but name is an utf8 mac name */
124 /* global static variable... */
126 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
135 if (aint > MACFILELEN)
142 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
145 utf8 = htonl(vol->v_mac->kTextEncoding); /* htonl(utf8) */
146 memcpy(data, &utf8, sizeof(utf8));
147 data += sizeof(utf8);
150 memcpy(data, &temp, sizeof(temp));
151 data += sizeof(temp);
154 memcpy( data, src, aint );
164 * FIXME: PDINFO is UTF8 and doesn't need adp
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)))
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)
181 #if AD_VERSION > AD_VERSION1
184 char stamp[ADEDLEN_PRIVSYN];
185 /* look in AD v2 header
186 * note inode and device are opaques and not in network order
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));
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));
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) {
208 case CNID_ERR_CLOSE: /* the db is closed */
211 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
212 afp_errno = AFPERR_PARAM;
215 afp_errno = AFPERR_PARAM;
218 afp_errno = AFPERR_MISC;
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
227 ad_setid(adp, st, aint, vol->v_stamp);
228 ad_flush(adp, ADFLAGS_HF);
235 /* -------------------------- */
236 int getmetadata(struct vol *vol,
238 struct path *path, struct dir *dir,
239 char *buf, int *buflen, struct adouble *adp, int attrbits )
241 char *data, *l_nameoff = NULL, *upath;
242 char *utf_nameoff = NULL;
247 u_char achar, fdType[4];
253 LOG(log_info, logtype_afpd, "begin getmetadata:");
256 upath = path->u_name;
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))) {
265 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
269 path->m_name = utompath(vol, upath, id, utf8_encoding());
272 while ( bitmap != 0 ) {
273 while (( bitmap & 1 ) == 0 ) {
281 ad_getattr(adp, &ashort);
282 } else if (*upath == '.') {
283 ashort = htons(ATTRBIT_INVISIBLE);
287 /* FIXME do we want a visual clue if the file is read only
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;
299 ashort = htons(ntohs(ashort) | attrbits);
300 memcpy(data, &ashort, sizeof( ashort ));
301 data += sizeof( ashort );
305 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
306 data += sizeof( u_int32_t );
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 );
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);
322 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324 memcpy(data, &aint, sizeof( int ));
325 data += sizeof( int );
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 );
336 get_finderinfo(path->m_name, adp, (char *)data);
338 if (*upath == '.') { /* make it invisible */
339 ashort = htons(FINDERINFO_INVISIBLE);
340 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
348 data += sizeof( u_int16_t );
352 memset(data, 0, sizeof(u_int16_t));
353 data += sizeof( u_int16_t );
357 memcpy(data, &id, sizeof( id ));
358 data += sizeof( id );
362 if (st->st_size > 0xffffffff)
365 aint = htonl( st->st_size );
366 memcpy(data, &aint, sizeof( aint ));
367 data += sizeof( aint );
372 if (adp->ad_rlen > 0xffffffff)
375 aint = htonl( adp->ad_rlen);
379 memcpy(data, &aint, sizeof( aint ));
380 data += sizeof( aint );
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;
393 data += sizeof( u_int16_t );
395 memcpy(data, &aint, sizeof( aint ));
396 data += sizeof( aint );
400 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
402 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
406 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
414 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
418 else if ( fdType[0] == 'p' ) {
420 ashort = (fdType[2] * 256) + fdType[3];
434 memcpy(data, &ashort, sizeof( ashort ));
435 data += sizeof( ashort );
436 memset(data, 0, sizeof( ashort ));
437 data += sizeof( ashort );
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 );
448 case FILPBIT_EXTRFLEN:
451 aint = htonl(adp->ad_rlen >> 32);
452 memcpy(data, &aint, sizeof( aint ));
453 data += sizeof( aint );
455 aint = htonl(adp->ad_rlen);
456 memcpy(data, &aint, sizeof( aint ));
457 data += sizeof( aint );
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 );
467 aint = htonl(st->st_mode);
468 memcpy( data, &aint, sizeof( aint ));
469 data += sizeof( aint );
471 accessmode( upath, &ma, dir , st);
473 *data++ = ma.ma_user;
474 *data++ = ma.ma_world;
475 *data++ = ma.ma_group;
476 *data++ = ma.ma_owner;
480 return( AFPERR_BITMAP );
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);
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);
495 *buflen = data - buf;
499 /* ----------------------- */
500 int getfilparams(struct vol *vol,
502 struct path *path, struct dir *dir,
503 char *buf, int *buflen )
505 struct adouble ad, *adp;
508 u_int16_t attrbits = 0;
513 LOG(log_info, logtype_default, "begin getfilparams:");
516 opened = PARAM_NEED_ADP(bitmap);
519 upath = path->u_name;
520 if ((of = of_findname(path))) {
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);
525 ad_init(&ad, vol->v_adouble);
529 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
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!
539 if ((bitmap & (1 << FILPBIT_ATTR))) {
540 if (!(attrbits & ATTRBIT_ROPEN)) {
542 if (!(attrbits & ATTRBIT_DOPEN)) {
547 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
549 ad_close( adp, ADFLAGS_HF );
552 LOG(log_info, logtype_afpd, "end getfilparams:");
558 /* ----------------------------- */
559 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
562 int ibuflen, *rbuflen;
564 struct adouble ad, *adp;
567 struct ofork *of = NULL;
569 int creatf, did, openf, retvalue = AFP_OK;
575 LOG(log_info, logtype_afpd, "begin afp_createfile:");
580 creatf = (unsigned char) *ibuf++;
582 memcpy(&vid, ibuf, sizeof( vid ));
583 ibuf += sizeof( vid );
585 if (NULL == ( vol = getvolbyvid( vid )) ) {
586 return( AFPERR_PARAM );
589 if (vol->v_flags & AFPVOL_RO)
592 memcpy(&did, ibuf, sizeof( did));
593 ibuf += sizeof( did );
595 if (NULL == ( dir = dirlookup( vol, did )) ) {
599 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
600 return get_afp_errno(AFPERR_PARAM);
603 if ( *s_path->m_name == '\0' ) {
604 return( AFPERR_BADTYPE );
607 upath = s_path->u_name;
608 if (0 != (ret = check_name(vol, upath)))
611 /* if upath is deleted we already in trouble anyway */
612 if ((of = of_findname(s_path))) {
615 ad_init(&ad, vol->v_adouble);
619 /* on a hard create, fail if file exists and is open */
622 openf = O_RDWR|O_CREAT|O_TRUNC;
624 /* on a soft create, if the file is open then ad_open won't fail
625 because open syscall is not called
630 openf = O_RDWR|O_CREAT|O_EXCL;
633 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
634 openf, 0666, adp) < 0 ) {
638 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
639 return ( AFPERR_NOOBJ );
641 return( AFPERR_EXIST );
643 return( AFPERR_ACCESS );
645 return( AFPERR_PARAM );
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;
654 /* FIXME with hard create on an existing file, we already
655 * corrupted the data file.
657 netatalk_unlink( upath );
658 ad_close( adp, ADFLAGS_DF );
659 return AFPERR_ACCESS;
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 );
673 if (vol->v_flags & AFPVOL_DROPBOX) {
674 retvalue = matchfile2dirperms(upath, vol, did);
676 #endif /* DROPKLUDGE */
678 setvoltime(obj, vol );
681 LOG(log_info, logtype_afpd, "end afp_createfile");
687 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
690 int ibuflen, *rbuflen;
696 u_int16_t vid, bitmap;
699 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
705 memcpy(&vid, ibuf, sizeof( vid ));
706 ibuf += sizeof( vid );
707 if (NULL == ( vol = getvolbyvid( vid )) ) {
708 return( AFPERR_PARAM );
711 if (vol->v_flags & AFPVOL_RO)
714 memcpy(&did, ibuf, sizeof( did ));
715 ibuf += sizeof( did );
716 if (NULL == ( dir = dirlookup( vol, did )) ) {
717 return afp_errno; /* was AFPERR_NOOBJ */
720 memcpy(&bitmap, ibuf, sizeof( bitmap ));
721 bitmap = ntohs( bitmap );
722 ibuf += sizeof( bitmap );
724 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
725 return get_afp_errno(AFPERR_PARAM);
728 if (path_isadir(s_path)) {
729 return( AFPERR_BADTYPE ); /* it's a directory */
732 if ( s_path->st_errno != 0 ) {
733 return( AFPERR_NOOBJ );
736 if ((u_long)ibuf & 1 ) {
740 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
741 setvoltime(obj, vol );
745 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
752 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
755 extern struct path Cur_Path;
757 int setfilparams(struct vol *vol,
758 struct path *path, u_int16_t bitmap, char *buf )
760 struct adouble ad, *adp;
763 int bit = 0, isad = 1, err = AFP_OK;
765 u_char achar, *fdType, xyy[4];
766 u_int16_t ashort, bshort;
770 int change_mdate = 0;
771 int change_parent_mdate = 0;
777 LOG(log_info, logtype_afpd, "begin setfilparams:");
780 upath = path->u_name;
781 if ((of = of_findname(path))) {
784 ad_init(&ad, vol->v_adouble);
788 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
789 return AFPERR_ACCESS;
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;
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 ));
805 while ( bitmap != 0 ) {
806 while (( bitmap & 1 ) == 0 ) {
814 memcpy(&ashort, buf, sizeof( ashort ));
815 ad_getattr(adp, &bshort);
816 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
817 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
821 if ((ashort & htons(ATTRBIT_INVISIBLE)))
822 change_parent_mdate = 1;
823 ad_setattr(adp, bshort);
824 buf += sizeof( ashort );
829 memcpy(&aint, buf, sizeof(aint));
830 ad_setdate(adp, AD_DATE_CREATE, aint);
831 buf += sizeof( aint );
835 memcpy(&newdate, buf, sizeof( newdate ));
836 buf += sizeof( newdate );
841 memcpy(&aint, buf, sizeof(aint));
842 ad_setdate(adp, AD_DATE_BACKUP, aint);
843 buf += sizeof( aint );
849 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
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)))
858 memcpy(buf, ufinderi, 8 );
861 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
865 /* Client needs to set the ProDOS file info for this file.
866 Use a defined string for TEXT to support crlf
867 translations and convert all else into pXYY per Inside
868 Appletalk. Always set the creator as "pdos". Changes
869 from original by Marsha Jackson. */
870 case FILPBIT_PDINFO :
871 if (afp_version < 30) { /* else it's UTF8 name */
874 /* Keep special case to support crlf translations */
875 if ((unsigned int) achar == 0x04) {
876 fdType = (u_char *)"TEXT";
879 xyy[0] = ( u_char ) 'p';
885 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
886 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
890 case FILPBIT_UNIXPR :
891 /* Skip the UIG/GID, no way to set them from OSX clients */
892 buf += sizeof( aint );
893 buf += sizeof( aint );
896 change_parent_mdate = 1;
897 memcpy( &aint, buf, sizeof( aint ));
898 buf += sizeof( aint );
901 setfilemode(path, aint);
905 goto setfilparam_done;
913 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
914 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
918 ad_setdate(adp, AD_DATE_MODIFY, newdate);
919 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
924 ad_flush( adp, ADFLAGS_HF );
925 ad_close( adp, ADFLAGS_HF );
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);
936 LOG(log_info, logtype_afpd, "end setfilparams:");
942 * renamefile and copyfile take the old and new unix pathnames
943 * and the new mac name.
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
951 int renamefile(src, dst, newname, noadouble, adp )
952 char *src, *dst, *newname;
956 char adsrc[ MAXPATHLEN + 1];
961 LOG(log_info, logtype_afpd, "begin renamefile:");
964 if ( unix_rename( src, dst ) < 0 ) {
967 return( AFPERR_NOOBJ );
970 return( AFPERR_ACCESS );
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
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 */
982 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
983 /* on error copyfile delete dest */
986 return deletefile(NULL, src, 0);
988 return( AFPERR_PARAM );
992 strcpy( adsrc, ad_path( src, 0 ));
994 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
999 if (errno == ENOENT) {
1002 if (stat(adsrc, &st)) /* source has no ressource fork, */
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.
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 )) )
1020 else { /* it's something else, bail out */
1024 /* try to undo the data fork rename,
1025 * we know we are on the same device
1028 unix_rename( dst, src );
1029 /* return the first error */
1032 return AFPERR_NOOBJ;
1035 return AFPERR_ACCESS ;
1037 return AFPERR_VLOCK;
1039 return AFPERR_PARAM ;
1044 /* don't care if we can't open the newly renamed ressource fork
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 );
1054 LOG(log_info, logtype_afpd, "end renamefile:");
1060 int copy_path_name(char *newname, char *ibuf)
1067 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
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
1085 memcpy(&hint, ibuf, sizeof(hint));
1086 ibuf += sizeof(hint);
1088 memcpy(&len16, ibuf, sizeof(len16));
1089 ibuf += sizeof(len16);
1090 plen = ntohs(len16);
1093 if (plen > AFPOBJ_TMPSIZ) {
1096 strncpy( newname, ibuf, plen );
1097 newname[ plen ] = '\0';
1098 if (strlen(newname) != plen) {
1107 /* -----------------------------------
1109 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1112 int ibuflen, *rbuflen;
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;
1123 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1129 memcpy(&svid, ibuf, sizeof( svid ));
1130 ibuf += sizeof( svid );
1131 if (NULL == ( vol = getvolbyvid( svid )) ) {
1132 return( AFPERR_PARAM );
1135 memcpy(&sdid, ibuf, sizeof( sdid ));
1136 ibuf += sizeof( sdid );
1137 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1141 memcpy(&dvid, ibuf, sizeof( dvid ));
1142 ibuf += sizeof( dvid );
1143 memcpy(&ddid, ibuf, sizeof( ddid ));
1144 ibuf += sizeof( ddid );
1146 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1147 return get_afp_errno(AFPERR_PARAM);
1149 if ( path_isadir(s_path) ) {
1150 return( AFPERR_BADTYPE );
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. */
1159 newname = obj->newtmp;
1160 strcpy( newname, s_path->m_name );
1162 if (of_findname(s_path))
1163 return AFPERR_DENYCONF;
1165 p = ctoupath( vol, curdir, newname );
1167 return AFPERR_PARAM;
1171 /* FIXME svid != dvid && dvid's user can't read svid */
1173 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1174 return( AFPERR_PARAM );
1177 if (vol->v_flags & AFPVOL_RO)
1178 return AFPERR_VLOCK;
1180 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1184 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1185 return get_afp_errno(AFPERR_NOOBJ);
1187 if ( *s_path->m_name != '\0' ) {
1189 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1191 path_error(s_path, AFPERR_PARAM);
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 );
1198 /* newname is always only a filename so curdir *is* its
1201 if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))) {
1202 return( AFPERR_PARAM );
1204 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1210 if (vol->v_flags & AFPVOL_DROPBOX) {
1211 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1213 #endif /* DROPKLUDGE */
1215 setvoltime(obj, vol );
1218 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1225 static __inline__ int copy_all(const int dfd, const void *buf,
1231 LOG(log_info, logtype_afpd, "begin copy_all:");
1234 while (buflen > 0) {
1235 if ((cc = write(dfd, buf, buflen)) < 0) {
1242 return AFPERR_DFULL;
1244 return AFPERR_VLOCK;
1246 return AFPERR_PARAM;
1253 LOG(log_info, logtype_afpd, "end copy_all:");
1259 /* -------------------------- */
1260 static int copy_fd(int dfd, int sfd)
1266 #ifdef SENDFILE_FLAVOR_LINUX
1269 if (fstat(sfd, &st) == 0) {
1270 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1272 case EINVAL: /* there's no guarantee that all fs support sendfile */
1277 return AFPERR_DFULL;
1279 return AFPERR_VLOCK;
1281 return AFPERR_PARAM;
1288 #endif /* SENDFILE_FLAVOR_LINUX */
1291 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1298 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1304 /* ----------------------------------
1305 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1306 * because we are doing it elsewhere.
1308 int copyfile(src, dst, newname, noadouble )
1309 char *src, *dst, *newname;
1310 const int noadouble;
1312 struct adouble ads, add;
1313 int len, err = AFP_OK;
1317 LOG(log_info, logtype_afpd, "begin copyfile:");
1320 ad_init(&ads, 0); /* OK */
1321 ad_init(&add, 0); /* FIXME */
1322 adflags = ADFLAGS_DF;
1324 adflags |= ADFLAGS_HF;
1327 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1330 return( AFPERR_NOOBJ );
1332 return( AFPERR_ACCESS );
1334 return( AFPERR_PARAM );
1337 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1338 ad_close( &ads, adflags );
1339 if (EEXIST != (err = errno)) {
1340 deletefile(NULL, dst, 0);
1344 return AFPERR_EXIST;
1346 return( AFPERR_NOOBJ );
1348 return( AFPERR_ACCESS );
1350 return AFPERR_VLOCK;
1352 return( AFPERR_PARAM );
1355 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1356 /* copy the data fork */
1357 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1361 len = strlen( newname );
1362 ad_setentrylen( &add, ADEID_NAME, len );
1363 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1366 ad_close( &ads, adflags );
1367 ad_flush( &add, adflags );
1368 if (ad_close( &add, adflags ) <0) {
1371 if (err != AFP_OK) {
1372 deletefile(NULL, dst, 0);
1375 return( AFPERR_NOOBJ );
1377 return( AFPERR_ACCESS );
1379 return( AFPERR_PARAM );
1384 LOG(log_info, logtype_afpd, "end copyfile:");
1391 /* -----------------------------------
1392 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1393 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1395 when deletefile is called we don't have lock on it, file is closed (for us)
1396 untrue if called by renamefile
1398 ad_open always try to open file RDWR first and ad_lock takes care of
1399 WRITE lock on read only file.
1401 int deletefile( vol, file, checkAttrib )
1407 int adflags, err = AFP_OK;
1410 LOG(log_info, logtype_afpd, "begin deletefile:");
1413 /* try to open both forks at once */
1414 adflags = ADFLAGS_DF|ADFLAGS_HF;
1416 ad_init(&ad, 0); /* OK */
1417 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1420 if (adflags == ADFLAGS_DF)
1421 return AFPERR_NOOBJ;
1423 /* that failed. now try to open just the data fork */
1424 adflags = ADFLAGS_DF;
1428 return AFPERR_ACCESS;
1430 return AFPERR_VLOCK;
1432 return( AFPERR_PARAM );
1435 break; /* from the while */
1438 * Does kFPDeleteInhibitBit (bit 8) set?
1440 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1443 ad_getattr(&ad, &bshort);
1444 if ((bshort & htons(ATTRBIT_NODELETE))) {
1445 ad_close( &ad, adflags );
1446 return(AFPERR_OLOCK);
1450 if ((adflags & ADFLAGS_HF) ) {
1451 /* FIXME we have a pb here because we want to know if a file is open
1452 * there's a 'priority inversion' if you can't open the ressource fork RW
1453 * you can delete it if it's open because you can't get a write lock.
1455 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1458 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1460 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1461 ad_close( &ad, adflags );
1462 return( AFPERR_BUSY );
1466 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1469 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1470 !(err = netatalk_unlink( file )) ) {
1472 if (vol && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1474 cnid_delete(vol->v_cdb, id);
1478 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1481 LOG(log_info, logtype_afpd, "end deletefile:");
1487 /* ------------------------------------ */
1488 /* return a file id */
1489 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1492 int ibuflen, *rbuflen;
1501 struct path *s_path;
1504 LOG(log_info, logtype_afpd, "begin afp_createid:");
1511 memcpy(&vid, ibuf, sizeof(vid));
1512 ibuf += sizeof(vid);
1514 if (NULL == ( vol = getvolbyvid( vid )) ) {
1515 return( AFPERR_PARAM);
1518 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1522 if (vol->v_flags & AFPVOL_RO)
1523 return AFPERR_VLOCK;
1525 memcpy(&did, ibuf, sizeof( did ));
1526 ibuf += sizeof(did);
1528 if (NULL == ( dir = dirlookup( vol, did )) ) {
1529 return afp_errno; /* was AFPERR_PARAM */
1532 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1533 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1536 if ( path_isadir(s_path) ) {
1537 return( AFPERR_BADTYPE );
1540 upath = s_path->u_name;
1541 switch (s_path->st_errno) {
1543 break; /* success */
1546 return AFPERR_ACCESS;
1548 return AFPERR_NOOBJ;
1550 return AFPERR_PARAM;
1553 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1554 memcpy(rbuf, &id, sizeof(id));
1555 *rbuflen = sizeof(id);
1556 return AFPERR_EXISTID;
1559 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1560 memcpy(rbuf, &id, sizeof(id));
1561 *rbuflen = sizeof(id);
1566 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1571 /* ------------------------------
1572 resolve a file id */
1573 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1576 int ibuflen, *rbuflen;
1584 u_int16_t vid, bitmap;
1586 static char buffer[12 + MAXPATHLEN + 1];
1587 int len = 12 + MAXPATHLEN + 1;
1590 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1596 memcpy(&vid, ibuf, sizeof(vid));
1597 ibuf += sizeof(vid);
1599 if (NULL == ( vol = getvolbyvid( vid )) ) {
1600 return( AFPERR_PARAM);
1603 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1607 memcpy(&id, ibuf, sizeof( id ));
1611 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1612 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1615 if (NULL == ( dir = dirlookup( vol, id )) ) {
1616 return AFPERR_NOID; /* idem AFPERR_PARAM */
1618 path.u_name = upath;
1619 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1623 return AFPERR_ACCESS;
1627 return AFPERR_PARAM;
1630 /* directories are bad */
1631 if (S_ISDIR(path.st.st_mode))
1632 return AFPERR_BADTYPE;
1634 memcpy(&bitmap, ibuf, sizeof(bitmap));
1635 bitmap = ntohs( bitmap );
1636 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1639 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1640 rbuf + sizeof(bitmap), &buflen))) {
1643 *rbuflen = buflen + sizeof(bitmap);
1644 memcpy(rbuf, ibuf, sizeof(bitmap));
1647 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1653 /* ------------------------------ */
1654 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1657 int ibuflen, *rbuflen;
1667 static char buffer[12 + MAXPATHLEN + 1];
1668 int len = 12 + MAXPATHLEN + 1;
1671 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1677 memcpy(&vid, ibuf, sizeof(vid));
1678 ibuf += sizeof(vid);
1680 if (NULL == ( vol = getvolbyvid( vid )) ) {
1681 return( AFPERR_PARAM);
1684 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1688 if (vol->v_flags & AFPVOL_RO)
1689 return AFPERR_VLOCK;
1691 memcpy(&id, ibuf, sizeof( id ));
1695 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1699 if (NULL == ( dir = dirlookup( vol, id )) ) {
1700 return( AFPERR_PARAM );
1704 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1708 return AFPERR_ACCESS;
1710 /* still try to delete the id */
1714 return AFPERR_PARAM;
1717 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1718 return AFPERR_BADTYPE;
1720 if (cnid_delete(vol->v_cdb, fileid)) {
1723 return AFPERR_VLOCK;
1726 return AFPERR_ACCESS;
1728 return AFPERR_PARAM;
1733 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1739 #define APPLETEMP ".AppleTempXXXXXX"
1741 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1744 int ibuflen, *rbuflen;
1746 struct stat srcst, destst;
1748 struct dir *dir, *sdir;
1749 char *spath, temp[17], *p;
1750 char *supath, *upath;
1755 struct adouble *adsp;
1756 struct adouble *addp;
1766 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1772 memcpy(&vid, ibuf, sizeof(vid));
1773 ibuf += sizeof(vid);
1775 if (NULL == ( vol = getvolbyvid( vid )) ) {
1776 return( AFPERR_PARAM);
1779 if (vol->v_flags & AFPVOL_RO)
1780 return AFPERR_VLOCK;
1782 /* source and destination dids */
1783 memcpy(&sid, ibuf, sizeof(sid));
1784 ibuf += sizeof(sid);
1785 memcpy(&did, ibuf, sizeof(did));
1786 ibuf += sizeof(did);
1789 if (NULL == (dir = dirlookup( vol, sid )) ) {
1790 return afp_errno; /* was AFPERR_PARAM */
1793 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1794 return get_afp_errno(AFPERR_NOOBJ);
1797 if ( path_isadir(path) ) {
1798 return( AFPERR_BADTYPE ); /* it's a dir */
1801 upath = path->u_name;
1802 switch (path->st_errno) {
1809 return AFPERR_ACCESS;
1811 return AFPERR_PARAM;
1813 ad_init(&ads, vol->v_adouble);
1815 if ((s_of = of_findname(path))) {
1816 /* reuse struct adouble so it won't break locks */
1819 memcpy(&srcst, &path->st, sizeof(struct stat));
1820 /* save some stuff */
1822 spath = obj->oldtmp;
1823 supath = obj->newtmp;
1824 strcpy(spath, path->m_name);
1825 strcpy(supath, upath); /* this is for the cnid changing */
1826 p = absupath( vol, sdir, upath);
1828 /* pathname too long */
1829 return AFPERR_PARAM ;
1832 /* look for the source cnid. if it doesn't exist, don't worry about
1834 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1836 if (NULL == ( dir = dirlookup( vol, did )) ) {
1837 return afp_errno; /* was AFPERR_PARAM */
1840 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1841 return get_afp_errno(AFPERR_NOOBJ);
1844 if ( path_isadir(path) ) {
1845 return( AFPERR_BADTYPE );
1848 /* FPExchangeFiles is the only call that can return the SameObj
1850 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1851 return AFPERR_SAMEOBJ;
1853 switch (path->st_errno) {
1860 return AFPERR_ACCESS;
1862 return AFPERR_PARAM;
1864 ad_init(&add, vol->v_adouble);
1866 if ((d_of = of_findname( path))) {
1867 /* reuse struct adouble so it won't break locks */
1870 memcpy(&destst, &path->st, sizeof(struct stat));
1872 /* they are not on the same device and at least one is open
1874 crossdev = (srcst.st_dev != destst.st_dev);
1875 if ((d_of || s_of) && crossdev)
1878 upath = path->u_name;
1879 /* look for destination id. */
1880 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
1882 /* construct a temp name.
1883 * NOTE: the temp file will be in the dest file's directory. it
1884 * will also be inaccessible from AFP. */
1885 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1889 /* now, quickly rename the file. we error if we can't. */
1890 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1891 goto err_exchangefile;
1892 of_rename(vol, s_of, sdir, spath, curdir, temp);
1894 /* rename destination to source */
1895 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1896 goto err_src_to_tmp;
1897 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1899 /* rename temp to destination */
1900 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1901 goto err_dest_to_src;
1902 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1904 /* id's need switching. src -> dest and dest -> src.
1905 * we need to re-stat() if it was a cross device copy.
1908 cnid_delete(vol->v_cdb, sid);
1911 cnid_delete(vol->v_cdb, did);
1913 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1914 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
1916 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1917 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
1922 err = AFPERR_ACCESS;
1927 goto err_temp_to_dest;
1931 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1937 /* all this stuff is so that we can unwind a failed operation
1940 /* rename dest to temp */
1941 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1942 of_rename(vol, s_of, curdir, upath, curdir, temp);
1945 /* rename source back to dest */
1946 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1947 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1950 /* rename temp back to source */
1951 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1952 of_rename(vol, s_of, curdir, temp, sdir, spath);