2 * $Id: file.c,v 1.91 2003-04-20 06:53:40 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>
52 #include <atalk/cnid.h>
54 #include "directory.h"
62 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
63 * field bytes subfield bytes
66 * ioFlFndrInfo 16 -> type 4 type field
67 * creator 4 creator field
68 * flags 2 finder flags:
70 * location 4 location in window
71 * folder 2 window that contains file
73 * ioFlXFndrInfo 16 -> iconID 2 icon id
75 * script 1 script system
77 * commentID 2 comment id
78 * putawayID 4 home directory id
81 const u_char ufinderi[] = {
82 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0
88 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
89 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
94 memcpy(data, ad_entry(adp, ADEID_FINDERI), 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, char *name, 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, 1)) || !(m = utompath(vol, u, 0))) {
135 if (aint > MACFILELEN)
142 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
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)
183 aint = cnid_add(vol->v_db, st, did, upath, len, aint);
184 /* Throw errors if cnid_add fails. */
185 if (aint == CNID_INVALID) {
187 case CNID_ERR_CLOSE: /* the db is closed */
190 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
191 afp_errno = AFPERR_PARAM;
194 afp_errno = AFPERR_PARAM;
197 afp_errno = AFPERR_MISC;
205 * First thing: DID and FNUMs are
206 * in the same space for purposes of enumerate (and several
207 * other wierd places). While we consider this Apple's bug,
208 * this is the work-around: In order to maintain constant and
209 * unique DIDs and FNUMs, we monotonically generate the DIDs
210 * during the session, and derive the FNUMs from the filesystem.
211 * Since the DIDs are small, we insure that the FNUMs are fairly
212 * large by setting thier high bits to the device number.
214 * AFS already does something very similar to this for the
215 * inode number, so we don't repeat the procedure.
218 * due to complaints over did's being non-persistent,
219 * here's the current hack to provide semi-persistent
221 * 1) we reserve the first bit for file ids.
222 * 2) the next 7 bits are for the device.
223 * 3) the remaining 24 bits are for the inode.
225 * both the inode and device information are actually hashes
226 * that are then truncated to the requisite bit length.
228 * it should be okay to use lstat to deal with symlinks.
231 if ( S_ISDIR(st->st_mode)) {
232 aint = htonl( vol->v_lastdid++ );
236 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
238 #else /* USE_LASTDID */
241 const struct stat *lstp;
243 lstp = lstat(upath, &lst) < 0 ? st : &lst;
244 aint = htonl(CNID(lstp, 1));
246 #endif /* USE_LASTDID */
251 /* -------------------------- */
252 int getmetadata(struct vol *vol,
254 struct path *path, struct dir *dir,
255 char *buf, int *buflen, struct adouble *adp, int attrbits )
257 char *data, *l_nameoff = NULL, *upath;
258 char *utf_nameoff = NULL;
262 u_char achar, fdType[4];
266 LOG(log_info, logtype_afpd, "begin getmetadata:");
269 upath = path->u_name;
273 while ( bitmap != 0 ) {
274 while (( bitmap & 1 ) == 0 ) {
282 ad_getattr(adp, &ashort);
283 } else if (*upath == '.') {
284 ashort = htons(ATTRBIT_INVISIBLE);
288 /* FIXME do we want a visual clue if the file is read only
291 accessmode( ".", &ma, dir , NULL);
292 if ((ma.ma_user & AR_UWRITE)) {
293 accessmode( upath, &ma, dir , st);
294 if (!(ma.ma_user & AR_UWRITE)) {
295 attrbits |= ATTRBIT_NOWRITE;
300 ashort = htons(ntohs(ashort) | attrbits);
301 memcpy(data, &ashort, sizeof( ashort ));
302 data += sizeof( ashort );
306 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
307 data += sizeof( u_int32_t );
311 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
312 aint = AD_DATE_FROM_UNIX(st->st_mtime);
313 memcpy(data, &aint, sizeof( aint ));
314 data += sizeof( aint );
318 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
319 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
320 aint = AD_DATE_FROM_UNIX(st->st_mtime);
323 aint = AD_DATE_FROM_UNIX(st->st_mtime);
325 memcpy(data, &aint, sizeof( int ));
326 data += sizeof( int );
330 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
331 aint = AD_DATE_START;
332 memcpy(data, &aint, sizeof( int ));
333 data += sizeof( int );
337 get_finderinfo(path->m_name, adp, (char *)data);
339 if (*upath == '.') { /* make it invisible */
340 ashort = htons(FINDERINFO_INVISIBLE);
341 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
349 data += sizeof( u_int16_t );
353 memset(data, 0, sizeof(u_int16_t));
354 data += sizeof( u_int16_t );
358 aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
361 memcpy(data, &aint, sizeof( aint ));
362 data += sizeof( aint );
366 if (st->st_size > 0xffffffff)
369 aint = htonl( st->st_size );
370 memcpy(data, &aint, sizeof( aint ));
371 data += sizeof( aint );
376 if (adp->ad_rlen > 0xffffffff)
379 aint = htonl( adp->ad_rlen);
383 memcpy(data, &aint, sizeof( aint ));
384 data += sizeof( aint );
387 /* Current client needs ProDOS info block for this file.
388 Use simple heuristic and let the Mac "type" string tell
389 us what the PD file code should be. Everything gets a
390 subtype of 0x0000 unless the original value was hashed
391 to "pXYZ" when we created it. See IA, Ver 2.
392 <shirsch@adelphia.net> */
393 case FILPBIT_PDINFO :
394 if (afp_version >= 30) { /* UTF8 name */
395 utf8 = kTextEncodingUTF8;
397 data += sizeof( u_int16_t );
399 memcpy(data, &aint, sizeof( aint ));
400 data += sizeof( aint );
404 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
406 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
414 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
418 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
422 else if ( fdType[0] == 'p' ) {
424 ashort = (fdType[2] * 256) + fdType[3];
438 memcpy(data, &ashort, sizeof( ashort ));
439 data += sizeof( ashort );
440 memset(data, 0, sizeof( ashort ));
441 data += sizeof( ashort );
444 case FILPBIT_EXTDFLEN:
445 aint = htonl(st->st_size >> 32);
446 memcpy(data, &aint, sizeof( aint ));
447 data += sizeof( aint );
448 aint = htonl(st->st_size);
449 memcpy(data, &aint, sizeof( aint ));
450 data += sizeof( aint );
452 case FILPBIT_EXTRFLEN:
455 aint = htonl(adp->ad_rlen >> 32);
456 memcpy(data, &aint, sizeof( aint ));
457 data += sizeof( aint );
459 aint = htonl(adp->ad_rlen);
460 memcpy(data, &aint, sizeof( aint ));
461 data += sizeof( aint );
464 return( AFPERR_BITMAP );
470 ashort = htons( data - buf );
471 memcpy(l_nameoff, &ashort, sizeof( ashort ));
472 data = set_name(vol, data, path->m_name, 0);
475 ashort = htons( data - buf );
476 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
477 data = set_name(vol, data, path->m_name, utf8);
479 *buflen = data - buf;
483 /* ----------------------- */
484 int getfilparams(struct vol *vol,
486 struct path *path, struct dir *dir,
487 char *buf, int *buflen )
489 struct adouble ad, *adp;
492 u_int16_t attrbits = 0;
497 LOG(log_info, logtype_default, "begin getfilparams:");
500 opened = PARAM_NEED_ADP(bitmap);
503 upath = path->u_name;
504 if ((of = of_findname(path))) {
506 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
507 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
509 memset(&ad, 0, sizeof(ad));
513 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
518 we need to check if the file is open by another process.
519 it's slow so we only do it if we have to:
520 - bitmap is requested.
521 - we don't already have the answer!
523 if ((bitmap & (1 << FILPBIT_ATTR))) {
524 if (!(attrbits & ATTRBIT_ROPEN)) {
526 if (!(attrbits & ATTRBIT_DOPEN)) {
531 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
533 ad_close( adp, ADFLAGS_HF );
536 LOG(log_info, logtype_afpd, "end getfilparams:");
542 /* ----------------------------- */
543 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
546 int ibuflen, *rbuflen;
548 struct adouble ad, *adp;
551 struct ofork *of = NULL;
553 int creatf, did, openf, retvalue = AFP_OK;
559 LOG(log_info, logtype_afpd, "begin afp_createfile:");
564 creatf = (unsigned char) *ibuf++;
566 memcpy(&vid, ibuf, sizeof( vid ));
567 ibuf += sizeof( vid );
569 if (NULL == ( vol = getvolbyvid( vid )) ) {
570 return( AFPERR_PARAM );
573 if (vol->v_flags & AFPVOL_RO)
576 memcpy(&did, ibuf, sizeof( did));
577 ibuf += sizeof( did );
579 if (NULL == ( dir = dirlookup( vol, did )) ) {
583 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
584 return get_afp_errno(AFPERR_PARAM);
587 if ( *s_path->m_name == '\0' ) {
588 return( AFPERR_BADTYPE );
591 upath = s_path->u_name;
592 if (0 != (ret = check_name(vol, upath)))
595 /* if upath is deleted we already in trouble anyway */
596 if ((of = of_findname(s_path))) {
599 memset(&ad, 0, sizeof(ad));
603 /* on a hard create, fail if file exists and is open */
606 openf = O_RDWR|O_CREAT|O_TRUNC;
608 /* on a soft create, if the file is open then ad_open won't fail
609 because open syscall is not called
614 openf = O_RDWR|O_CREAT|O_EXCL;
617 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
618 openf, 0666, adp) < 0 ) {
620 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
621 return ( AFPERR_NOOBJ );
623 return( AFPERR_EXIST );
625 return( AFPERR_ACCESS );
627 return( AFPERR_PARAM );
630 if ( ad_hfileno( adp ) == -1 ) {
631 /* on noadouble volumes, just creating the data fork is ok */
632 if (vol_noadouble(vol)) {
633 ad_close( adp, ADFLAGS_DF );
634 goto createfile_done;
636 /* FIXME with hard create on an existing file, we already
637 * corrupted the data file.
639 netatalk_unlink( upath );
640 ad_close( adp, ADFLAGS_DF );
641 return AFPERR_ACCESS;
644 path = s_path->m_name;
645 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
646 memcpy(ad_entry( adp, ADEID_NAME ), path,
647 ad_getentrylen( adp, ADEID_NAME ));
648 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
649 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
655 if (vol->v_flags & AFPVOL_DROPBOX) {
656 retvalue = matchfile2dirperms(upath, vol, did);
658 #endif /* DROPKLUDGE */
660 setvoltime(obj, vol );
663 LOG(log_info, logtype_afpd, "end afp_createfile");
669 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
672 int ibuflen, *rbuflen;
678 u_int16_t vid, bitmap;
681 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
687 memcpy(&vid, ibuf, sizeof( vid ));
688 ibuf += sizeof( vid );
689 if (NULL == ( vol = getvolbyvid( vid )) ) {
690 return( AFPERR_PARAM );
693 if (vol->v_flags & AFPVOL_RO)
696 memcpy(&did, ibuf, sizeof( did ));
697 ibuf += sizeof( did );
698 if (NULL == ( dir = dirlookup( vol, did )) ) {
699 return afp_errno; /* was AFPERR_NOOBJ */
702 memcpy(&bitmap, ibuf, sizeof( bitmap ));
703 bitmap = ntohs( bitmap );
704 ibuf += sizeof( bitmap );
706 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
707 return get_afp_errno(AFPERR_PARAM);
710 if (path_isadir(s_path)) {
711 return( AFPERR_BADTYPE ); /* it's a directory */
714 if ( s_path->st_errno != 0 ) {
715 return( AFPERR_NOOBJ );
718 if ((u_long)ibuf & 1 ) {
722 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
723 setvoltime(obj, vol );
727 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
734 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
737 extern struct path Cur_Path;
739 int setfilparams(struct vol *vol,
740 struct path *path, u_int16_t bitmap, char *buf )
742 struct adouble ad, *adp;
745 int bit = 0, isad = 1, err = AFP_OK;
747 u_char achar, *fdType, xyy[4];
748 u_int16_t ashort, bshort;
752 int change_mdate = 0;
753 int change_parent_mdate = 0;
759 LOG(log_info, logtype_afpd, "begin setfilparams:");
762 upath = path->u_name;
763 if ((of = of_findname(path))) {
766 memset(&ad, 0, sizeof(ad));
770 if (check_access(upath, OPENACC_WR ) < 0) {
771 return AFPERR_ACCESS;
774 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
775 O_RDWR|O_CREAT, 0666, adp) < 0) {
776 /* for some things, we don't need an adouble header */
777 if (bitmap & ~(1<<FILPBIT_MDATE)) {
778 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
781 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
782 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
783 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
784 ad_getentrylen( adp, ADEID_NAME ));
787 while ( bitmap != 0 ) {
788 while (( bitmap & 1 ) == 0 ) {
796 memcpy(&ashort, buf, sizeof( ashort ));
797 ad_getattr(adp, &bshort);
798 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
799 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
803 if ((ashort & htons(ATTRBIT_INVISIBLE)))
804 change_parent_mdate = 1;
805 ad_setattr(adp, bshort);
806 buf += sizeof( ashort );
811 memcpy(&aint, buf, sizeof(aint));
812 ad_setdate(adp, AD_DATE_CREATE, aint);
813 buf += sizeof( aint );
817 memcpy(&newdate, buf, sizeof( newdate ));
818 buf += sizeof( newdate );
823 memcpy(&aint, buf, sizeof(aint));
824 ad_setdate(adp, AD_DATE_BACKUP, aint);
825 buf += sizeof( aint );
831 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
833 ((em = getextmap( path->m_name )) &&
834 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
835 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
836 || ((em = getdefextmap()) &&
837 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
838 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
840 memcpy(buf, ufinderi, 8 );
843 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
847 /* Client needs to set the ProDOS file info for this file.
848 Use a defined string for TEXT to support crlf
849 translations and convert all else into pXYY per Inside
850 Appletalk. Always set the creator as "pdos". Changes
851 from original by Marsha Jackson. */
852 case FILPBIT_PDINFO :
853 if (afp_version < 30) { /* else it's UTF8 name */
856 /* Keep special case to support crlf translations */
857 if ((unsigned int) achar == 0x04) {
858 fdType = (u_char *)"TEXT";
861 xyy[0] = ( u_char ) 'p';
867 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
868 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
874 goto setfilparam_done;
882 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
883 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
887 ad_setdate(adp, AD_DATE_MODIFY, newdate);
888 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
893 ad_flush( adp, ADFLAGS_HF );
894 ad_close( adp, ADFLAGS_HF );
898 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
899 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
900 bitmap = 1<<FILPBIT_MDATE;
901 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
905 LOG(log_info, logtype_afpd, "end setfilparams:");
911 * renamefile and copyfile take the old and new unix pathnames
912 * and the new mac name.
914 * src the source path
915 * dst the dest filename in current dir
916 * newname the dest mac name
917 * adp adouble struct of src file, if open, or & zeroed one
920 int renamefile(src, dst, newname, noadouble, adp )
921 char *src, *dst, *newname;
925 char adsrc[ MAXPATHLEN + 1];
930 LOG(log_info, logtype_afpd, "begin renamefile:");
933 if ( unix_rename( src, dst ) < 0 ) {
936 return( AFPERR_NOOBJ );
939 return( AFPERR_ACCESS );
942 case EXDEV : /* Cross device move -- try copy */
943 /* NOTE: with open file it's an error because after the copy we will
944 * get two files, it's fixable for our process (eg reopen the new file, get the
945 * locks, and so on. But it doesn't solve the case with a second process
947 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
948 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
949 return AFPERR_OLOCK; /* little lie */
951 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
952 /* on error copyfile delete dest */
955 return deletefile(NULL, src, 0);
957 return( AFPERR_PARAM );
961 strcpy( adsrc, ad_path( src, 0 ));
963 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
968 if (errno == ENOENT) {
971 if (stat(adsrc, &st)) /* source has no ressource fork, */
974 /* We are here because :
975 * -there's no dest folder.
976 * -there's no .AppleDouble in the dest folder.
977 * if we use the struct adouble passed in parameter it will not
978 * create .AppleDouble if the file is already opened, so we
979 * use a diff one, it's not a pb,ie it's not the same file, yet.
981 memset(&ad, 0, sizeof(ad));
982 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
983 ad_close(&ad, ADFLAGS_HF);
984 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
989 else { /* it's something else, bail out */
993 /* try to undo the data fork rename,
994 * we know we are on the same device
997 unix_rename( dst, src );
998 /* return the first error */
1001 return AFPERR_NOOBJ;
1004 return AFPERR_ACCESS ;
1006 return AFPERR_VLOCK;
1008 return AFPERR_PARAM ;
1013 /* don't care if we can't open the newly renamed ressource fork
1015 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1016 len = strlen( newname );
1017 ad_setentrylen( adp, ADEID_NAME, len );
1018 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1019 ad_flush( adp, ADFLAGS_HF );
1020 ad_close( adp, ADFLAGS_HF );
1023 LOG(log_info, logtype_afpd, "end renamefile:");
1029 int copy_path_name(char *newname, char *ibuf)
1036 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1042 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1043 strncpy( newname, ibuf, plen );
1044 newname[ plen ] = '\0';
1045 if (strlen(newname) != plen) {
1046 /* there's \0 in newname, e.g. it's a pathname not
1054 memcpy(&hint, ibuf, sizeof(hint));
1055 ibuf += sizeof(hint);
1057 memcpy(&len16, ibuf, sizeof(len16));
1058 ibuf += sizeof(len16);
1059 plen = ntohs(len16);
1062 if (plen > AFPOBJ_TMPSIZ) {
1065 strncpy( newname, ibuf, plen );
1066 newname[ plen ] = '\0';
1067 if (strlen(newname) != plen) {
1076 /* -----------------------------------
1078 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1081 int ibuflen, *rbuflen;
1085 char *newname, *p, *upath;
1086 struct path *s_path;
1087 u_int32_t sdid, ddid;
1088 int err, retvalue = AFP_OK;
1089 u_int16_t svid, dvid;
1092 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1098 memcpy(&svid, ibuf, sizeof( svid ));
1099 ibuf += sizeof( svid );
1100 if (NULL == ( vol = getvolbyvid( svid )) ) {
1101 return( AFPERR_PARAM );
1104 memcpy(&sdid, ibuf, sizeof( sdid ));
1105 ibuf += sizeof( sdid );
1106 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1110 memcpy(&dvid, ibuf, sizeof( dvid ));
1111 ibuf += sizeof( dvid );
1112 memcpy(&ddid, ibuf, sizeof( ddid ));
1113 ibuf += sizeof( ddid );
1115 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1116 return get_afp_errno(AFPERR_PARAM);
1118 if ( path_isadir(s_path) ) {
1119 return( AFPERR_BADTYPE );
1122 /* don't allow copies when the file is open.
1123 * XXX: the spec only calls for read/deny write access.
1124 * however, copyfile doesn't have any of that info,
1125 * and locks need to stay coherent. as a result,
1126 * we just balk if the file is opened already. */
1128 newname = obj->newtmp;
1129 strcpy( newname, s_path->m_name );
1131 if (of_findname(s_path))
1132 return AFPERR_DENYCONF;
1134 p = ctoupath( vol, curdir, newname );
1136 return AFPERR_PARAM;
1140 /* FIXME svid != dvid && dvid's user can't read svid */
1142 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1143 return( AFPERR_PARAM );
1146 if (vol->v_flags & AFPVOL_RO)
1147 return AFPERR_VLOCK;
1149 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1153 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1154 return get_afp_errno(AFPERR_NOOBJ);
1156 if ( *s_path->m_name != '\0' ) {
1158 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1160 path_error(s_path, AFPERR_PARAM);
1163 /* one of the handful of places that knows about the path type */
1164 if (copy_path_name(newname, ibuf) < 0) {
1165 return( AFPERR_PARAM );
1168 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1169 return( AFPERR_PARAM );
1171 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1177 if (vol->v_flags & AFPVOL_DROPBOX) {
1178 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1180 #endif /* DROPKLUDGE */
1182 setvoltime(obj, vol );
1185 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1192 static __inline__ int copy_all(const int dfd, const void *buf,
1198 LOG(log_info, logtype_afpd, "begin copy_all:");
1201 while (buflen > 0) {
1202 if ((cc = write(dfd, buf, buflen)) < 0) {
1209 return AFPERR_DFULL;
1211 return AFPERR_VLOCK;
1213 return AFPERR_PARAM;
1220 LOG(log_info, logtype_afpd, "end copy_all:");
1226 /* -------------------------- */
1227 static int copy_fd(int dfd, int sfd)
1233 #ifdef SENDFILE_FLAVOR_LINUX
1236 if (fstat(sfd, &st) == 0) {
1237 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1239 case EINVAL: /* there's no guarantee that all fs support sendfile */
1244 return AFPERR_DFULL;
1246 return AFPERR_VLOCK;
1248 return AFPERR_PARAM;
1255 #endif /* SENDFILE_FLAVOR_LINUX */
1258 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1265 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1271 /* ----------------------------------
1272 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1273 * because we are doing it elsewhere.
1275 int copyfile(src, dst, newname, noadouble )
1276 char *src, *dst, *newname;
1277 const int noadouble;
1279 struct adouble ads, add;
1280 int len, err = AFP_OK;
1284 LOG(log_info, logtype_afpd, "begin copyfile:");
1287 memset(&ads, 0, sizeof(ads));
1288 memset(&add, 0, sizeof(add));
1289 adflags = ADFLAGS_DF;
1291 adflags |= ADFLAGS_HF;
1294 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1297 return( AFPERR_NOOBJ );
1299 return( AFPERR_ACCESS );
1301 return( AFPERR_PARAM );
1304 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1305 ad_close( &ads, adflags );
1306 if (EEXIST != (err = errno)) {
1307 deletefile(NULL, dst, 0);
1311 return AFPERR_EXIST;
1313 return( AFPERR_NOOBJ );
1315 return( AFPERR_ACCESS );
1317 return AFPERR_VLOCK;
1319 return( AFPERR_PARAM );
1322 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1323 /* copy the data fork */
1324 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1328 len = strlen( newname );
1329 ad_setentrylen( &add, ADEID_NAME, len );
1330 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1333 ad_close( &ads, adflags );
1334 ad_flush( &add, adflags );
1335 if (ad_close( &add, adflags ) <0) {
1338 if (err != AFP_OK) {
1339 deletefile(NULL, dst, 0);
1342 return( AFPERR_NOOBJ );
1344 return( AFPERR_ACCESS );
1346 return( AFPERR_PARAM );
1351 LOG(log_info, logtype_afpd, "end copyfile:");
1358 /* -----------------------------------
1359 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1360 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1362 when deletefile is called we don't have lock on it, file is closed (for us)
1363 untrue if called by renamefile
1365 ad_open always try to open file RDWR first and ad_lock takes care of
1366 WRITE lock on read only file.
1368 int deletefile( vol, file, checkAttrib )
1374 int adflags, err = AFP_OK;
1377 LOG(log_info, logtype_afpd, "begin deletefile:");
1380 /* try to open both forks at once */
1381 adflags = ADFLAGS_DF|ADFLAGS_HF;
1383 memset(&ad, 0, sizeof(ad));
1384 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1387 if (adflags == ADFLAGS_DF)
1388 return AFPERR_NOOBJ;
1390 /* that failed. now try to open just the data fork */
1391 adflags = ADFLAGS_DF;
1395 return AFPERR_ACCESS;
1397 return AFPERR_VLOCK;
1399 return( AFPERR_PARAM );
1402 break; /* from the while */
1405 * Does kFPDeleteInhibitBit (bit 8) set?
1407 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1410 ad_getattr(&ad, &bshort);
1411 if ((bshort & htons(ATTRBIT_NODELETE))) {
1412 ad_close( &ad, adflags );
1413 return(AFPERR_OLOCK);
1417 if ((adflags & ADFLAGS_HF) ) {
1418 /* FIXME we have a pb here because we want to know if a file is open
1419 * there's a 'priority inversion' if you can't open the ressource fork RW
1420 * you can delete it if it's open because you can't get a write lock.
1422 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1425 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1427 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1428 ad_close( &ad, adflags );
1429 return( AFPERR_BUSY );
1433 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1436 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1437 !(err = netatalk_unlink( file )) ) {
1438 #ifdef CNID_DB /* get rid of entry */
1440 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1442 cnid_delete(vol->v_db, id);
1444 #endif /* CNID_DB */
1447 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1450 LOG(log_info, logtype_afpd, "end deletefile:");
1456 /* ------------------------------------ */
1458 /* return a file id */
1459 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1462 int ibuflen, *rbuflen;
1471 struct path *s_path;
1474 LOG(log_info, logtype_afpd, "begin afp_createid:");
1481 memcpy(&vid, ibuf, sizeof(vid));
1482 ibuf += sizeof(vid);
1484 if (NULL == ( vol = getvolbyvid( vid )) ) {
1485 return( AFPERR_PARAM);
1488 if (vol->v_db == NULL) {
1492 if (vol->v_flags & AFPVOL_RO)
1493 return AFPERR_VLOCK;
1495 memcpy(&did, ibuf, sizeof( did ));
1496 ibuf += sizeof(did);
1498 if (NULL == ( dir = dirlookup( vol, did )) ) {
1499 return afp_errno; /* was AFPERR_PARAM */
1502 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1503 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1506 if ( path_isadir(s_path) ) {
1507 return( AFPERR_BADTYPE );
1510 upath = s_path->u_name;
1511 switch (s_path->st_errno) {
1513 break; /* success */
1516 return AFPERR_ACCESS;
1518 return AFPERR_NOOBJ;
1520 return AFPERR_PARAM;
1523 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1524 memcpy(rbuf, &id, sizeof(id));
1525 *rbuflen = sizeof(id);
1526 return AFPERR_EXISTID;
1529 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1530 memcpy(rbuf, &id, sizeof(id));
1531 *rbuflen = sizeof(id);
1536 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1541 /* ------------------------------
1542 resolve a file id */
1543 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1546 int ibuflen, *rbuflen;
1554 u_int16_t vid, bitmap;
1556 static char buffer[12 + MAXPATHLEN + 1];
1557 int len = 12 + MAXPATHLEN + 1;
1560 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1566 memcpy(&vid, ibuf, sizeof(vid));
1567 ibuf += sizeof(vid);
1569 if (NULL == ( vol = getvolbyvid( vid )) ) {
1570 return( AFPERR_PARAM);
1573 if (vol->v_db == NULL) {
1577 memcpy(&id, ibuf, sizeof( id ));
1580 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1581 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1584 if (NULL == ( dir = dirlookup( vol, id )) ) {
1585 return AFPERR_NOID; /* idem AFPERR_PARAM */
1587 path.u_name = upath;
1588 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1592 return AFPERR_ACCESS;
1596 return AFPERR_PARAM;
1599 /* directories are bad */
1600 if (S_ISDIR(path.st.st_mode))
1601 return AFPERR_BADTYPE;
1603 memcpy(&bitmap, ibuf, sizeof(bitmap));
1604 bitmap = ntohs( bitmap );
1605 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1608 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1609 rbuf + sizeof(bitmap), &buflen))) {
1612 *rbuflen = buflen + sizeof(bitmap);
1613 memcpy(rbuf, ibuf, sizeof(bitmap));
1616 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1622 /* ------------------------------ */
1623 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1626 int ibuflen, *rbuflen;
1636 static char buffer[12 + MAXPATHLEN + 1];
1637 int len = 12 + MAXPATHLEN + 1;
1640 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1646 memcpy(&vid, ibuf, sizeof(vid));
1647 ibuf += sizeof(vid);
1649 if (NULL == ( vol = getvolbyvid( vid )) ) {
1650 return( AFPERR_PARAM);
1653 if (vol->v_db == NULL) {
1657 if (vol->v_flags & AFPVOL_RO)
1658 return AFPERR_VLOCK;
1660 memcpy(&id, ibuf, sizeof( id ));
1664 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1668 if (NULL == ( dir = dirlookup( vol, id )) ) {
1669 return( AFPERR_PARAM );
1673 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1677 return AFPERR_ACCESS;
1679 /* still try to delete the id */
1683 return AFPERR_PARAM;
1686 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1687 return AFPERR_BADTYPE;
1689 if (cnid_delete(vol->v_db, fileid)) {
1692 return AFPERR_VLOCK;
1695 return AFPERR_ACCESS;
1697 return AFPERR_PARAM;
1702 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1707 #endif /* CNID_DB */
1709 #define APPLETEMP ".AppleTempXXXXXX"
1711 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1714 int ibuflen, *rbuflen;
1716 struct stat srcst, destst;
1718 struct dir *dir, *sdir;
1719 char *spath, temp[17], *p;
1720 char *supath, *upath;
1725 struct adouble *adsp;
1726 struct adouble *addp;
1733 #endif /* CNID_DB */
1738 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1744 memcpy(&vid, ibuf, sizeof(vid));
1745 ibuf += sizeof(vid);
1747 if (NULL == ( vol = getvolbyvid( vid )) ) {
1748 return( AFPERR_PARAM);
1751 if (vol->v_flags & AFPVOL_RO)
1752 return AFPERR_VLOCK;
1754 /* source and destination dids */
1755 memcpy(&sid, ibuf, sizeof(sid));
1756 ibuf += sizeof(sid);
1757 memcpy(&did, ibuf, sizeof(did));
1758 ibuf += sizeof(did);
1761 if (NULL == (dir = dirlookup( vol, sid )) ) {
1762 return afp_errno; /* was AFPERR_PARAM */
1765 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1766 return get_afp_errno(AFPERR_NOOBJ);
1769 if ( path_isadir(path) ) {
1770 return( AFPERR_BADTYPE ); /* it's a dir */
1773 upath = path->u_name;
1774 switch (path->st_errno) {
1781 return AFPERR_ACCESS;
1783 return AFPERR_PARAM;
1785 memset(&ads, 0, sizeof(ads));
1787 if ((s_of = of_findname(path))) {
1788 /* reuse struct adouble so it won't break locks */
1791 memcpy(&srcst, &path->st, sizeof(struct stat));
1792 /* save some stuff */
1794 spath = obj->oldtmp;
1795 supath = obj->newtmp;
1796 strcpy(spath, path->m_name);
1797 strcpy(supath, upath); /* this is for the cnid changing */
1798 p = absupath( vol, sdir, upath);
1800 /* pathname too long */
1801 return AFPERR_PARAM ;
1804 /* look for the source cnid. if it doesn't exist, don't worry about
1807 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1808 slen = strlen(supath));
1809 #endif /* CNID_DB */
1811 if (NULL == ( dir = dirlookup( vol, did )) ) {
1812 return afp_errno; /* was AFPERR_PARAM */
1815 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1816 return get_afp_errno(AFPERR_NOOBJ);
1819 if ( path_isadir(path) ) {
1820 return( AFPERR_BADTYPE );
1823 /* FPExchangeFiles is the only call that can return the SameObj
1825 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1826 return AFPERR_SAMEOBJ;
1828 switch (path->st_errno) {
1835 return AFPERR_ACCESS;
1837 return AFPERR_PARAM;
1839 memset(&add, 0, sizeof(add));
1841 if ((d_of = of_findname( path))) {
1842 /* reuse struct adouble so it won't break locks */
1845 memcpy(&destst, &path->st, sizeof(struct stat));
1847 /* they are not on the same device and at least one is open
1849 crossdev = (srcst.st_dev != destst.st_dev);
1850 if ((d_of || s_of) && crossdev)
1853 upath = path->u_name;
1855 /* look for destination id. */
1856 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1857 dlen = strlen(upath));
1858 #endif /* CNID_DB */
1860 /* construct a temp name.
1861 * NOTE: the temp file will be in the dest file's directory. it
1862 * will also be inaccessible from AFP. */
1863 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1867 /* now, quickly rename the file. we error if we can't. */
1868 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1869 goto err_exchangefile;
1870 of_rename(vol, s_of, sdir, spath, curdir, temp);
1872 /* rename destination to source */
1873 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1874 goto err_src_to_tmp;
1875 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1877 /* rename temp to destination */
1878 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1879 goto err_dest_to_src;
1880 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1883 /* id's need switching. src -> dest and dest -> src.
1884 * we need to re-stat() if it was a cross device copy.
1887 cnid_delete(vol->v_db, sid);
1890 cnid_delete(vol->v_db, did);
1892 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1893 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1895 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1896 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1901 err = AFPERR_ACCESS;
1906 goto err_temp_to_dest;
1908 #endif /* CNID_DB */
1911 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1917 /* all this stuff is so that we can unwind a failed operation
1922 /* rename dest to temp */
1923 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1924 of_rename(vol, s_of, curdir, upath, curdir, temp);
1927 /* rename source back to dest */
1928 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1929 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1932 /* rename temp back to source */
1933 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1934 of_rename(vol, s_of, curdir, temp, sdir, spath);