2 * $Id: file.c,v 1.87 2003-03-09 19:55:34 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 )) ) {
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 ) {
621 return( AFPERR_EXIST );
623 return( AFPERR_ACCESS );
625 return( AFPERR_PARAM );
628 if ( ad_hfileno( adp ) == -1 ) {
629 /* on noadouble volumes, just creating the data fork is ok */
630 if (vol_noadouble(vol))
631 goto createfile_done;
632 /* FIXME with hard create on an existing file, we already
633 * corrupted the data file.
635 netatalk_unlink( upath );
636 ad_close( adp, ADFLAGS_DF );
637 return AFPERR_ACCESS;
640 path = s_path->m_name;
641 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
642 memcpy(ad_entry( adp, ADEID_NAME ), path,
643 ad_getentrylen( adp, ADEID_NAME ));
644 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
645 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
651 if (vol->v_flags & AFPVOL_DROPBOX) {
652 retvalue = matchfile2dirperms(upath, vol, did);
654 #endif /* DROPKLUDGE */
656 setvoltime(obj, vol );
659 LOG(log_info, logtype_afpd, "end afp_createfile");
665 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
668 int ibuflen, *rbuflen;
674 u_int16_t vid, bitmap;
677 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
683 memcpy(&vid, ibuf, sizeof( vid ));
684 ibuf += sizeof( vid );
685 if (NULL == ( vol = getvolbyvid( vid )) ) {
686 return( AFPERR_PARAM );
689 if (vol->v_flags & AFPVOL_RO)
692 memcpy(&did, ibuf, sizeof( did ));
693 ibuf += sizeof( did );
694 if (NULL == ( dir = dirlookup( vol, did )) ) {
695 return afp_errno; /* was AFPERR_NOOBJ */
698 memcpy(&bitmap, ibuf, sizeof( bitmap ));
699 bitmap = ntohs( bitmap );
700 ibuf += sizeof( bitmap );
702 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
706 if (path_isadir(s_path)) {
707 return( AFPERR_BADTYPE ); /* it's a directory */
710 if ((u_long)ibuf & 1 ) {
714 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
715 setvoltime(obj, vol );
719 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
726 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
729 extern struct path Cur_Path;
731 int setfilparams(struct vol *vol,
732 struct path *path, u_int16_t bitmap, char *buf )
734 struct adouble ad, *adp;
737 int bit = 0, isad = 1, err = AFP_OK;
739 u_char achar, *fdType, xyy[4];
740 u_int16_t ashort, bshort;
744 int change_mdate = 0;
745 int change_parent_mdate = 0;
751 LOG(log_info, logtype_afpd, "begin setfilparams:");
754 upath = path->u_name;
755 if ((of = of_findname(path))) {
758 memset(&ad, 0, sizeof(ad));
762 if (check_access(upath, OPENACC_WR ) < 0) {
763 return AFPERR_ACCESS;
766 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
767 O_RDWR|O_CREAT, 0666, adp) < 0) {
768 /* for some things, we don't need an adouble header */
769 if (bitmap & ~(1<<FILPBIT_MDATE)) {
770 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
773 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
774 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
775 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
776 ad_getentrylen( adp, ADEID_NAME ));
779 while ( bitmap != 0 ) {
780 while (( bitmap & 1 ) == 0 ) {
788 memcpy(&ashort, buf, sizeof( ashort ));
789 ad_getattr(adp, &bshort);
790 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
791 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
795 if ((ashort & htons(ATTRBIT_INVISIBLE)))
796 change_parent_mdate = 1;
797 ad_setattr(adp, bshort);
798 buf += sizeof( ashort );
803 memcpy(&aint, buf, sizeof(aint));
804 ad_setdate(adp, AD_DATE_CREATE, aint);
805 buf += sizeof( aint );
809 memcpy(&newdate, buf, sizeof( newdate ));
810 buf += sizeof( newdate );
815 memcpy(&aint, buf, sizeof(aint));
816 ad_setdate(adp, AD_DATE_BACKUP, aint);
817 buf += sizeof( aint );
823 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
825 ((em = getextmap( path->m_name )) &&
826 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
827 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
828 || ((em = getdefextmap()) &&
829 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
830 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
832 memcpy(buf, ufinderi, 8 );
835 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
839 /* Client needs to set the ProDOS file info for this file.
840 Use a defined string for TEXT to support crlf
841 translations and convert all else into pXYY per Inside
842 Appletalk. Always set the creator as "pdos". Changes
843 from original by Marsha Jackson. */
844 case FILPBIT_PDINFO :
845 if (afp_version < 30) { /* else it's UTF8 name */
848 /* Keep special case to support crlf translations */
849 if ((unsigned int) achar == 0x04) {
850 fdType = (u_char *)"TEXT";
853 xyy[0] = ( u_char ) 'p';
859 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
860 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
866 goto setfilparam_done;
874 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
875 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
879 ad_setdate(adp, AD_DATE_MODIFY, newdate);
880 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
885 ad_flush( adp, ADFLAGS_HF );
886 ad_close( adp, ADFLAGS_HF );
890 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
891 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
892 bitmap = 1<<FILPBIT_MDATE;
893 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
897 LOG(log_info, logtype_afpd, "end setfilparams:");
903 * renamefile and copyfile take the old and new unix pathnames
904 * and the new mac name.
906 * src the source path
907 * dst the dest filename in current dir
908 * newname the dest mac name
909 * adp adouble struct of src file, if open, or & zeroed one
912 int renamefile(src, dst, newname, noadouble, adp )
913 char *src, *dst, *newname;
917 char adsrc[ MAXPATHLEN + 1];
922 LOG(log_info, logtype_afpd, "begin renamefile:");
925 if ( unix_rename( src, dst ) < 0 ) {
928 return( AFPERR_NOOBJ );
931 return( AFPERR_ACCESS );
934 case EXDEV : /* Cross device move -- try copy */
935 /* NOTE: with open file it's an error because after the copy we will
936 * get two files, it's fixable for our process (eg reopen the new file, get the
937 * locks, and so on. But it doesn't solve the case with a second process
939 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
940 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
941 return AFPERR_OLOCK; /* little lie */
943 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
944 /* on error copyfile delete dest */
947 return deletefile(NULL, src, 0);
949 return( AFPERR_PARAM );
953 strcpy( adsrc, ad_path( src, 0 ));
955 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
960 if (errno == ENOENT) {
963 if (stat(adsrc, &st)) /* source has no ressource fork, */
966 /* We are here because :
967 * -there's no dest folder.
968 * -there's no .AppleDouble in the dest folder.
969 * if we use the struct adouble passed in parameter it will not
970 * create .AppleDouble if the file is already opened, so we
971 * use a diff one, it's not a pb,ie it's not the same file, yet.
973 memset(&ad, 0, sizeof(ad));
974 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
975 ad_close(&ad, ADFLAGS_HF);
976 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
981 else { /* it's something else, bail out */
985 /* try to undo the data fork rename,
986 * we know we are on the same device
989 unix_rename( dst, src );
990 /* return the first error */
996 return AFPERR_ACCESS ;
1000 return AFPERR_PARAM ;
1005 /* don't care if we can't open the newly renamed ressource fork
1007 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1008 len = strlen( newname );
1009 ad_setentrylen( adp, ADEID_NAME, len );
1010 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1011 ad_flush( adp, ADFLAGS_HF );
1012 ad_close( adp, ADFLAGS_HF );
1015 LOG(log_info, logtype_afpd, "end renamefile:");
1021 int copy_path_name(char *newname, char *ibuf)
1028 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1034 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1035 strncpy( newname, ibuf, plen );
1036 newname[ plen ] = '\0';
1037 if (strlen(newname) != plen) {
1038 /* there's \0 in newname, e.g. it's a pathname not
1046 memcpy(&hint, ibuf, sizeof(hint));
1047 ibuf += sizeof(hint);
1049 memcpy(&len16, ibuf, sizeof(len16));
1050 ibuf += sizeof(len16);
1051 plen = ntohs(len16);
1053 strncpy( newname, ibuf, plen );
1054 newname[ plen ] = '\0';
1055 if (strlen(newname) != plen) {
1064 /* -----------------------------------
1066 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1069 int ibuflen, *rbuflen;
1073 char *newname, *p, *upath;
1074 struct path *s_path;
1075 u_int32_t sdid, ddid;
1076 int err, retvalue = AFP_OK;
1077 u_int16_t svid, dvid;
1080 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1086 memcpy(&svid, ibuf, sizeof( svid ));
1087 ibuf += sizeof( svid );
1088 if (NULL == ( vol = getvolbyvid( svid )) ) {
1089 return( AFPERR_PARAM );
1092 memcpy(&sdid, ibuf, sizeof( sdid ));
1093 ibuf += sizeof( sdid );
1094 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1098 memcpy(&dvid, ibuf, sizeof( dvid ));
1099 ibuf += sizeof( dvid );
1100 memcpy(&ddid, ibuf, sizeof( ddid ));
1101 ibuf += sizeof( ddid );
1103 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1106 if ( path_isadir(s_path) ) {
1107 return( AFPERR_BADTYPE );
1110 /* don't allow copies when the file is open.
1111 * XXX: the spec only calls for read/deny write access.
1112 * however, copyfile doesn't have any of that info,
1113 * and locks need to stay coherent. as a result,
1114 * we just balk if the file is opened already. */
1116 newname = obj->newtmp;
1117 strcpy( newname, s_path->m_name );
1119 if (of_findname(s_path))
1120 return AFPERR_DENYCONF;
1122 p = ctoupath( vol, curdir, newname );
1124 return AFPERR_PARAM;
1128 /* FIXME svid != dvid && dvid's user can't read svid */
1130 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1131 return( AFPERR_PARAM );
1134 if (vol->v_flags & AFPVOL_RO)
1135 return AFPERR_VLOCK;
1137 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1141 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1144 if ( *s_path->m_name != '\0' ) {
1145 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1148 /* one of the handful of places that knows about the path type */
1149 if (copy_path_name(newname, ibuf) < 0) {
1150 return( AFPERR_PARAM );
1153 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1154 return( AFPERR_PARAM );
1156 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1162 if (vol->v_flags & AFPVOL_DROPBOX) {
1163 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1165 #endif /* DROPKLUDGE */
1167 setvoltime(obj, vol );
1170 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1177 static __inline__ int copy_all(const int dfd, const void *buf,
1183 LOG(log_info, logtype_afpd, "begin copy_all:");
1186 while (buflen > 0) {
1187 if ((cc = write(dfd, buf, buflen)) < 0) {
1194 return AFPERR_DFULL;
1196 return AFPERR_VLOCK;
1198 return AFPERR_PARAM;
1205 LOG(log_info, logtype_afpd, "end copy_all:");
1211 /* -------------------------- */
1212 static int copy_fd(int dfd, int sfd)
1218 #ifdef SENDFILE_FLAVOR_LINUX
1221 if (fstat(sfd, &st) == 0) {
1222 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1224 case EINVAL: /* there's no guarantee that all fs support sendfile */
1229 return AFPERR_DFULL;
1231 return AFPERR_VLOCK;
1233 return AFPERR_PARAM;
1240 #endif /* SENDFILE_FLAVOR_LINUX */
1243 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1250 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1256 /* ----------------------------------
1257 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1258 * because we are doing it elsewhere.
1260 int copyfile(src, dst, newname, noadouble )
1261 char *src, *dst, *newname;
1262 const int noadouble;
1264 struct adouble ads, add;
1265 int len, err = AFP_OK;
1269 LOG(log_info, logtype_afpd, "begin copyfile:");
1272 memset(&ads, 0, sizeof(ads));
1273 memset(&add, 0, sizeof(add));
1274 adflags = ADFLAGS_DF;
1276 adflags |= ADFLAGS_HF;
1279 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1282 return( AFPERR_NOOBJ );
1284 return( AFPERR_ACCESS );
1286 return( AFPERR_PARAM );
1289 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1290 ad_close( &ads, adflags );
1291 if (EEXIST != (err = errno)) {
1292 deletefile(NULL, dst, 0);
1296 return AFPERR_EXIST;
1298 return( AFPERR_NOOBJ );
1300 return( AFPERR_ACCESS );
1302 return AFPERR_VLOCK;
1304 return( AFPERR_PARAM );
1307 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1308 /* copy the data fork */
1309 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1313 len = strlen( newname );
1314 ad_setentrylen( &add, ADEID_NAME, len );
1315 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1318 ad_close( &ads, adflags );
1319 ad_flush( &add, adflags );
1320 if (ad_close( &add, adflags ) <0) {
1323 if (err != AFP_OK) {
1324 deletefile(NULL, dst, 0);
1327 return( AFPERR_NOOBJ );
1329 return( AFPERR_ACCESS );
1331 return( AFPERR_PARAM );
1336 LOG(log_info, logtype_afpd, "end copyfile:");
1343 /* -----------------------------------
1344 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1345 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1347 when deletefile is called we don't have lock on it, file is closed (for us)
1348 untrue if called by renamefile
1350 ad_open always try to open file RDWR first and ad_lock takes care of
1351 WRITE lock on read only file.
1353 int deletefile( vol, file, checkAttrib )
1359 int adflags, err = AFP_OK;
1362 LOG(log_info, logtype_afpd, "begin deletefile:");
1365 /* try to open both forks at once */
1366 adflags = ADFLAGS_DF|ADFLAGS_HF;
1368 memset(&ad, 0, sizeof(ad));
1369 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1372 if (adflags == ADFLAGS_DF)
1373 return AFPERR_NOOBJ;
1375 /* that failed. now try to open just the data fork */
1376 adflags = ADFLAGS_DF;
1380 return AFPERR_ACCESS;
1382 return AFPERR_VLOCK;
1384 return( AFPERR_PARAM );
1387 break; /* from the while */
1390 * Does kFPDeleteInhibitBit (bit 8) set?
1392 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1395 ad_getattr(&ad, &bshort);
1396 if ((bshort & htons(ATTRBIT_NODELETE))) {
1397 ad_close( &ad, adflags );
1398 return(AFPERR_OLOCK);
1402 if ((adflags & ADFLAGS_HF) ) {
1403 /* FIXME we have a pb here because we want to know if a file is open
1404 * there's a 'priority inversion' if you can't open the ressource fork RW
1405 * you can delete it if it's open because you can't get a write lock.
1407 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1410 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1412 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1413 ad_close( &ad, adflags );
1414 return( AFPERR_BUSY );
1418 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1421 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1422 !(err = netatalk_unlink( file )) ) {
1423 #ifdef CNID_DB /* get rid of entry */
1425 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1427 cnid_delete(vol->v_db, id);
1429 #endif /* CNID_DB */
1432 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1435 LOG(log_info, logtype_afpd, "end deletefile:");
1441 /* ------------------------------------ */
1443 /* return a file id */
1444 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1447 int ibuflen, *rbuflen;
1456 struct path *s_path;
1459 LOG(log_info, logtype_afpd, "begin afp_createid:");
1466 memcpy(&vid, ibuf, sizeof(vid));
1467 ibuf += sizeof(vid);
1469 if (NULL == ( vol = getvolbyvid( vid )) ) {
1470 return( AFPERR_PARAM);
1473 if (vol->v_db == NULL) {
1477 if (vol->v_flags & AFPVOL_RO)
1478 return AFPERR_VLOCK;
1480 memcpy(&did, ibuf, sizeof( did ));
1481 ibuf += sizeof(did);
1483 if (NULL == ( dir = dirlookup( vol, did )) ) {
1484 return( AFPERR_PARAM );
1487 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1488 return afp_errno; /* was AFPERR_PARAM */
1491 if ( path_isadir(s_path) ) {
1492 return( AFPERR_BADTYPE );
1495 upath = s_path->u_name;
1496 switch (s_path->st_errno) {
1498 break; /* success */
1501 return AFPERR_ACCESS;
1503 return AFPERR_NOOBJ;
1505 return AFPERR_PARAM;
1508 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1509 memcpy(rbuf, &id, sizeof(id));
1510 *rbuflen = sizeof(id);
1511 return AFPERR_EXISTID;
1514 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1515 memcpy(rbuf, &id, sizeof(id));
1516 *rbuflen = sizeof(id);
1521 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1526 /* ------------------------------
1527 resolve a file id */
1528 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1531 int ibuflen, *rbuflen;
1539 u_int16_t vid, bitmap;
1541 static char buffer[12 + MAXPATHLEN + 1];
1542 int len = 12 + MAXPATHLEN + 1;
1545 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1551 memcpy(&vid, ibuf, sizeof(vid));
1552 ibuf += sizeof(vid);
1554 if (NULL == ( vol = getvolbyvid( vid )) ) {
1555 return( AFPERR_PARAM);
1558 if (vol->v_db == NULL) {
1562 memcpy(&id, ibuf, sizeof( id ));
1565 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1566 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1569 if (NULL == ( dir = dirlookup( vol, id )) ) {
1570 return AFPERR_NOID; /* idem AFPERR_PARAM */
1572 path.u_name = upath;
1573 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1577 return AFPERR_ACCESS;
1581 return AFPERR_PARAM;
1584 /* directories are bad */
1585 if (S_ISDIR(path.st.st_mode))
1586 return AFPERR_BADTYPE;
1588 memcpy(&bitmap, ibuf, sizeof(bitmap));
1589 bitmap = ntohs( bitmap );
1590 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1593 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1594 rbuf + sizeof(bitmap), &buflen))) {
1597 *rbuflen = buflen + sizeof(bitmap);
1598 memcpy(rbuf, ibuf, sizeof(bitmap));
1601 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1607 /* ------------------------------ */
1608 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1611 int ibuflen, *rbuflen;
1621 static char buffer[12 + MAXPATHLEN + 1];
1622 int len = 12 + MAXPATHLEN + 1;
1625 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1631 memcpy(&vid, ibuf, sizeof(vid));
1632 ibuf += sizeof(vid);
1634 if (NULL == ( vol = getvolbyvid( vid )) ) {
1635 return( AFPERR_PARAM);
1638 if (vol->v_db == NULL) {
1642 if (vol->v_flags & AFPVOL_RO)
1643 return AFPERR_VLOCK;
1645 memcpy(&id, ibuf, sizeof( id ));
1649 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1653 if (NULL == ( dir = dirlookup( vol, id )) ) {
1654 return( AFPERR_PARAM );
1658 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1662 return AFPERR_ACCESS;
1664 /* still try to delete the id */
1668 return AFPERR_PARAM;
1671 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1672 return AFPERR_BADTYPE;
1674 if (cnid_delete(vol->v_db, fileid)) {
1677 return AFPERR_VLOCK;
1680 return AFPERR_ACCESS;
1682 return AFPERR_PARAM;
1687 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1692 #endif /* CNID_DB */
1694 #define APPLETEMP ".AppleTempXXXXXX"
1696 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1699 int ibuflen, *rbuflen;
1701 struct stat srcst, destst;
1703 struct dir *dir, *sdir;
1704 char *spath, temp[17], *p;
1705 char *supath, *upath;
1710 struct adouble *adsp;
1711 struct adouble *addp;
1718 #endif /* CNID_DB */
1723 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1729 memcpy(&vid, ibuf, sizeof(vid));
1730 ibuf += sizeof(vid);
1732 if (NULL == ( vol = getvolbyvid( vid )) ) {
1733 return( AFPERR_PARAM);
1736 if (vol->v_flags & AFPVOL_RO)
1737 return AFPERR_VLOCK;
1739 /* source and destination dids */
1740 memcpy(&sid, ibuf, sizeof(sid));
1741 ibuf += sizeof(sid);
1742 memcpy(&did, ibuf, sizeof(did));
1743 ibuf += sizeof(did);
1746 if (NULL == (dir = dirlookup( vol, sid )) ) {
1747 return( AFPERR_PARAM );
1750 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1751 return afp_errno; /* was AFPERR_PARAM */
1754 if ( path_isadir(path) ) {
1755 return( AFPERR_BADTYPE ); /* it's a dir */
1758 upath = path->u_name;
1759 switch (path->st_errno) {
1766 return AFPERR_ACCESS;
1768 return AFPERR_PARAM;
1770 memset(&ads, 0, sizeof(ads));
1772 if ((s_of = of_findname(path))) {
1773 /* reuse struct adouble so it won't break locks */
1776 memcpy(&srcst, &path->st, sizeof(struct stat));
1777 /* save some stuff */
1779 spath = obj->oldtmp;
1780 supath = obj->newtmp;
1781 strcpy(spath, path->m_name);
1782 strcpy(supath, upath); /* this is for the cnid changing */
1783 p = absupath( vol, sdir, upath);
1785 /* pathname too long */
1786 return AFPERR_PARAM ;
1789 /* look for the source cnid. if it doesn't exist, don't worry about
1792 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1793 slen = strlen(supath));
1794 #endif /* CNID_DB */
1796 if (NULL == ( dir = dirlookup( vol, did )) ) {
1797 return( AFPERR_PARAM );
1800 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1801 return( AFPERR_PARAM );
1804 if ( path_isadir(path) ) {
1805 return( AFPERR_BADTYPE );
1808 /* FPExchangeFiles is the only call that can return the SameObj
1810 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1811 return AFPERR_SAMEOBJ;
1813 switch (path->st_errno) {
1820 return AFPERR_ACCESS;
1822 return AFPERR_PARAM;
1824 memset(&add, 0, sizeof(add));
1826 if ((d_of = of_findname( path))) {
1827 /* reuse struct adouble so it won't break locks */
1830 memcpy(&destst, &path->st, sizeof(struct stat));
1832 /* they are not on the same device and at least one is open
1834 crossdev = (srcst.st_dev != destst.st_dev);
1835 if ((d_of || s_of) && crossdev)
1838 upath = path->u_name;
1840 /* look for destination id. */
1841 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1842 dlen = strlen(upath));
1843 #endif /* CNID_DB */
1845 /* construct a temp name.
1846 * NOTE: the temp file will be in the dest file's directory. it
1847 * will also be inaccessible from AFP. */
1848 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1852 /* now, quickly rename the file. we error if we can't. */
1853 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1854 goto err_exchangefile;
1855 of_rename(vol, s_of, sdir, spath, curdir, temp);
1857 /* rename destination to source */
1858 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1859 goto err_src_to_tmp;
1860 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1862 /* rename temp to destination */
1863 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1864 goto err_dest_to_src;
1865 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1868 /* id's need switching. src -> dest and dest -> src.
1869 * we need to re-stat() if it was a cross device copy.
1872 cnid_delete(vol->v_db, sid);
1875 cnid_delete(vol->v_db, did);
1877 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1878 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1880 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1881 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1886 err = AFPERR_ACCESS;
1891 goto err_temp_to_dest;
1893 #endif /* CNID_DB */
1896 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1902 /* all this stuff is so that we can unwind a failed operation
1907 /* rename dest to temp */
1908 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1909 of_rename(vol, s_of, curdir, upath, curdir, temp);
1912 /* rename source back to dest */
1913 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1914 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1917 /* rename temp back to source */
1918 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1919 of_rename(vol, s_of, curdir, temp, sdir, spath);