2 * $Id: file.c,v 1.26 2001-08-15 01:37:34 srittau 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 #endif /* HAVE_FCNTL_H */
26 #include <sys/syslog.h>
27 #include <sys/types.h>
29 #include <sys/param.h>
32 #include <netatalk/endian.h>
33 #include <atalk/adouble.h>
34 #include <atalk/afp.h>
35 #include <atalk/util.h>
37 #include <atalk/cnid.h>
39 #include "directory.h"
47 /* check for mtab DID code */
49 #include "parse_mtab.h"
55 #endif /* FORCE_UIDGID */
57 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
58 * field bytes subfield bytes
61 * ioFlFndrInfo 16 -> type 4 type field
62 * creator 4 creator field
63 * flags 2 finder flags:
65 * location 4 location in window
66 * folder 2 window that contains file
68 * ioFlXFndrInfo 16 -> iconID 2 icon id
70 * script 1 script system
72 * commentID 2 comment id
73 * putawayID 4 home directory id
76 const u_char ufinderi[] = {
77 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
78 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0
83 int getfilparams(struct vol *vol,
85 char *path, struct dir *dir, struct stat *st,
86 char *buf, int *buflen )
89 struct stat hst, lst, *lstp;
90 #else /* USE_LASTDID */
92 #endif /* USE_LASTDID */
93 struct adouble ad, *adp;
96 char *data, *nameoff = NULL, *upath;
97 int bit = 0, isad = 1;
100 u_char achar, fdType[4];
103 syslog(LOG_INFO, "begin getfilparams:");
106 upath = mtoupath(vol, path);
107 if ((of = of_findname(vol, curdir, path))) {
110 memset(&ad, 0, sizeof(ad));
114 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
116 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
117 syslog( LOG_ERR, "getfilparams fstat: %s", strerror(errno) );
121 while ( bitmap != 0 ) {
122 while (( bitmap & 1 ) == 0 ) {
130 ad_getattr(adp, &ashort);
131 } else if (*upath == '.') {
132 ashort = htons(ATTRBIT_INVISIBLE);
135 memcpy(data, &ashort, sizeof( ashort ));
136 data += sizeof( u_short );
140 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
141 data += sizeof( u_int32_t );
145 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
146 aint = AD_DATE_FROM_UNIX(st->st_mtime);
147 memcpy(data, &aint, sizeof( aint ));
148 data += sizeof( aint );
152 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
153 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
154 (hst.st_mtime < st->st_mtime)) {
155 aint = AD_DATE_FROM_UNIX(st->st_mtime);
158 aint = AD_DATE_FROM_UNIX(st->st_mtime);
160 memcpy(data, &aint, sizeof( int ));
161 data += sizeof( int );
165 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
166 aint = AD_DATE_START;
167 memcpy(data, &aint, sizeof( int ));
168 data += sizeof( int );
173 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
175 memcpy(data, ufinderi, 32);
176 if (*upath == '.') { /* make it invisible */
177 ashort = htons(FINDERINFO_INVISIBLE);
178 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
182 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
183 ufinderi, 8 ) == 0)) &&
184 (em = getextmap( path ))) {
185 memcpy(data, em->em_type, sizeof( em->em_type ));
186 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
193 data += sizeof( u_int16_t );
197 memset(data, 0, sizeof(u_int16_t));
198 data += sizeof( u_int16_t );
204 /* find out if we have a fixed did already */
205 aint = cnid_lookup(vol->v_db, st, dir->d_did, upath,
209 /* look in AD v2 header */
212 #if AD_VERSION > AD_VERSION1
214 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
215 #endif /* AD_VERSION > AD_VERSION1 */
218 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
219 strlen(upath), aint);
225 * What a fucking mess. First thing: DID and FNUMs are
226 * in the same space for purposes of enumerate (and several
227 * other wierd places). While we consider this Apple's bug,
228 * this is the work-around: In order to maintain constant and
229 * unique DIDs and FNUMs, we monotonically generate the DIDs
230 * during the session, and derive the FNUMs from the filesystem.
231 * Since the DIDs are small, we insure that the FNUMs are fairly
232 * large by setting thier high bits to the device number.
234 * AFS already does something very similar to this for the
235 * inode number, so we don't repeat the procedure.
238 * due to complaints over did's being non-persistent,
239 * here's the current hack to provide semi-persistent
241 * 1) we reserve the first bit for file ids.
242 * 2) the next 7 bits are for the device.
243 * 3) the remaining 24 bits are for the inode.
245 * both the inode and device information are actually hashes
246 * that are then truncated to the requisite bit length.
248 * it should be okay to use lstat to deal with symlinks.
251 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
252 #else /* USE_LASTDID */
253 lstp = lstat(upath, &lst) < 0 ? st : &lst;
255 aint = htonl( afpd_st_cnid ( lstp ) );
257 aint = htonl(CNID(lstp, 1));
258 #endif /* DID_MTAB */
259 #endif /* USE_LASTDID */
262 memcpy(data, &aint, sizeof( aint ));
263 data += sizeof( aint );
267 aint = htonl( st->st_size );
268 memcpy(data, &aint, sizeof( aint ));
269 data += sizeof( aint );
274 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
278 memcpy(data, &aint, sizeof( aint ));
279 data += sizeof( aint );
282 /* Current client needs ProDOS info block for this file.
283 Use simple heuristic and let the Mac "type" string tell
284 us what the PD file code should be. Everything gets a
285 subtype of 0x0000 unless the original value was hashed
286 to "pXYZ" when we created it. See IA, Ver 2.
288 case FILPBIT_PDINFO :
290 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
292 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
296 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
300 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
304 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
308 else if ( fdType[0] == 'p' ) {
310 ashort = (fdType[2] * 256) + fdType[3];
324 memcpy(data, &ashort, sizeof( ashort ));
325 data += sizeof( ashort );
326 memset(data, 0, sizeof( ashort ));
327 data += sizeof( ashort );
332 ad_close( adp, ADFLAGS_HF );
334 return( AFPERR_BITMAP );
340 ashort = htons( data - buf );
341 memcpy(nameoff, &ashort, sizeof( ashort ));
342 if ((aint = strlen( path )) > MACFILELEN)
345 memcpy(data, path, aint );
349 ad_close( adp, ADFLAGS_HF );
351 *buflen = data - buf;
354 syslog(LOG_INFO, "end getfilparams:");
360 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
363 int ibuflen, *rbuflen;
366 struct adouble ad, *adp;
371 int creatf, did, openf, retvalue = AFP_OK;
375 #endif /* FORCE_UIDGID */
378 syslog(LOG_INFO, "begin afp_createfile:");
383 creatf = (unsigned char) *ibuf++;
385 memcpy(&vid, ibuf, sizeof( vid ));
386 ibuf += sizeof( vid );
388 if (( vol = getvolbyvid( vid )) == NULL ) {
389 return( AFPERR_PARAM );
392 if (vol->v_flags & AFPVOL_RO)
395 memcpy(&did, ibuf, sizeof( did));
396 ibuf += sizeof( did );
398 if (( dir = dirsearch( vol, did )) == NULL ) {
399 return( AFPERR_NOOBJ );
402 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
403 return( AFPERR_NOOBJ );
406 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
407 strpbrk(path, MSWINDOWS_BADCHARS))
410 upath = mtoupath(vol, path);
412 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
415 if (!validupath(vol, upath))
418 if ((of = of_findname(vol, curdir, path))) {
421 memset(&ad, 0, sizeof(ad));
425 /* on a hard create, fail if file exists and is open */
426 if ((stat(upath, &st) == 0) && of)
428 openf = O_RDWR|O_CREAT|O_TRUNC;
430 openf = O_RDWR|O_CREAT|O_EXCL;
435 /* preserve current euid, egid */
436 save_uidgid ( uidgid );
438 /* perform all switching of users */
441 #endif /* FORCE_UIDGID */
443 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
444 openf, 0666, adp) < 0 ) {
448 /* bring everything back to old euid, egid */
449 restore_uidgid ( uidgid );
450 #endif /* FORCE_UIDGID */
451 return( AFPERR_EXIST );
454 /* bring everything back to old euid, egid */
455 restore_uidgid ( uidgid );
456 #endif /* FORCE_UIDGID */
457 return( AFPERR_ACCESS );
459 /* on noadouble volumes, just creating the data fork is ok */
460 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
461 goto createfile_done;
465 /* bring everything back to old euid, egid */
466 restore_uidgid ( uidgid );
467 #endif /* FORCE_UIDGID */
468 return( AFPERR_PARAM );
472 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
473 memcpy(ad_entry( adp, ADEID_NAME ), path,
474 ad_getentrylen( adp, ADEID_NAME ));
475 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
476 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
481 if (vol->v_flags & AFPVOL_DROPBOX) {
482 retvalue = matchfile2dirperms(upath, vol, did);
484 #endif /* DROPKLUDGE */
486 setvoltime(obj, vol );
489 syslog(LOG_INFO, "end afp_createfile");
493 /* bring everything back to old euid, egid */
494 restore_uidgid ( uidgid );
495 #endif /* FORCE_UIDGID */
500 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
503 int ibuflen, *rbuflen;
509 u_int16_t vid, bitmap;
512 syslog(LOG_INFO, "begin afp_setfilparams:");
518 memcpy(&vid, ibuf, sizeof( vid ));
519 ibuf += sizeof( vid );
520 if (( vol = getvolbyvid( vid )) == NULL ) {
521 return( AFPERR_PARAM );
524 if (vol->v_flags & AFPVOL_RO)
527 memcpy(&did, ibuf, sizeof( did ));
528 ibuf += sizeof( did );
529 if (( dir = dirsearch( vol, did )) == NULL ) {
530 return( AFPERR_NOOBJ );
533 memcpy(&bitmap, ibuf, sizeof( bitmap ));
534 bitmap = ntohs( bitmap );
535 ibuf += sizeof( bitmap );
537 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
538 return( AFPERR_NOOBJ );
541 if ((u_long)ibuf & 1 ) {
545 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
546 setvoltime(obj, vol );
550 syslog(LOG_INFO, "end afp_setfilparams:");
557 int setfilparams(struct vol *vol,
558 char *path, u_int16_t bitmap, char *buf )
560 struct adouble ad, *adp;
563 int bit = 0, isad = 1, err = AFP_OK;
565 u_char achar, *fdType, xyy[4];
566 u_int16_t ashort, bshort;
573 uidgid = malloc(sizeof(uidgidset));
574 #endif /* FORCE_UIDGID */
577 syslog(LOG_INFO, "begin setfilparams:");
580 upath = mtoupath(vol, path);
581 if ((of = of_findname(vol, curdir, path))) {
584 memset(&ad, 0, sizeof(ad));
589 save_uidgid ( uidgid );
591 #endif /* FORCE_UIDGID */
593 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
594 O_RDWR|O_CREAT, 0666, adp) < 0) {
595 /* for some things, we don't need an adouble header */
596 if (bitmap & ~(1<<FILPBIT_MDATE)) {
598 restore_uidgid ( uidgid );
599 #endif /* FORCE_UIDGID */
600 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
603 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
604 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
605 memcpy(ad_entry( adp, ADEID_NAME ), path,
606 ad_getentrylen( adp, ADEID_NAME ));
609 while ( bitmap != 0 ) {
610 while (( bitmap & 1 ) == 0 ) {
617 memcpy(&ashort, buf, sizeof( ashort ));
618 ad_getattr(adp, &bshort);
619 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
620 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
624 ad_setattr(adp, bshort);
625 buf += sizeof( ashort );
629 memcpy(&aint, buf, sizeof(aint));
630 ad_setdate(adp, AD_DATE_CREATE, aint);
631 buf += sizeof( aint );
635 memcpy(&aint, buf, sizeof( aint ));
637 ad_setdate(adp, AD_DATE_MODIFY, aint);
638 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
640 buf += sizeof( aint );
644 memcpy(&aint, buf, sizeof(aint));
645 ad_setdate(adp, AD_DATE_BACKUP, aint);
646 buf += sizeof( aint );
650 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
651 && (em = getextmap( path )) &&
652 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
653 (memcmp(buf + 4, em->em_creator,
654 sizeof( em->em_creator )) == 0)) {
655 memcpy(buf, ufinderi, 8 );
657 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
661 /* Client needs to set the ProDOS file info for this file.
662 Use defined strings for the simple cases, and convert
663 all else into pXYY per Inside Appletalk. Always set
664 the creator as "pdos". <shirsch@ibm.net> */
665 case FILPBIT_PDINFO :
668 memcpy(&ashort, buf, sizeof( ashort ));
669 ashort = ntohs( ashort );
672 switch ( (unsigned int) achar )
675 fdType = ( u_char *) "TEXT";
679 fdType = ( u_char *) "PSYS";
683 fdType = ( u_char *) "PS16";
687 fdType = ( u_char *) "BINA";
691 xyy[0] = ( u_char ) 'p';
693 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
694 xyy[3] = ( u_char ) ashort & 0xff;
699 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
700 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
706 goto setfilparam_done;
715 ad_flush( adp, ADFLAGS_HF );
716 ad_close( adp, ADFLAGS_HF );
719 restore_uidgid ( uidgid );
720 #endif /* FORCE_UIDGID */
725 syslog(LOG_INFO, "end setfilparams:");
732 * renamefile and copyfile take the old and new unix pathnames
733 * and the new mac name.
734 * NOTE: if we have to copy a file instead of renaming it, locks
737 int renamefile(src, dst, newname, noadouble )
738 char *src, *dst, *newname;
742 char adsrc[ MAXPATHLEN + 1];
746 * Note that this is only checking the existance of the data file,
747 * not the header file. The thinking is that if the data file doesn't
748 * exist, but the header file does, the right thing to do is remove
749 * the data file silently.
752 /* existence check moved to afp_moveandrename */
755 syslog (LOG_INFO, "begin renamefile:");
758 if ( rename( src, dst ) < 0 ) {
761 return( AFPERR_NOOBJ );
764 return( AFPERR_ACCESS );
767 case EXDEV : /* Cross device move -- try copy */
768 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
772 return deletefile( src );
774 return( AFPERR_PARAM );
778 strcpy( adsrc, ad_path( src, 0 ));
781 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
786 /* check for a source appledouble header. if it exists, make
787 * a dest appledouble directory and do the rename again. */
788 memset(&ad, 0, sizeof(ad));
789 if (rc || stat(adsrc, &st) ||
790 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
793 ad_close(&ad, ADFLAGS_HF);
797 return( AFPERR_ACCESS );
801 return( AFPERR_PARAM );
805 memset(&ad, 0, sizeof(ad));
806 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
809 return( AFPERR_NOOBJ );
811 return( AFPERR_ACCESS );
815 return( AFPERR_PARAM );
819 len = strlen( newname );
820 ad_setentrylen( &ad, ADEID_NAME, len );
821 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
822 ad_flush( &ad, ADFLAGS_HF );
823 ad_close( &ad, ADFLAGS_HF );
826 syslog (LOG_INFO, "end renamefile:");
832 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
835 int ibuflen, *rbuflen;
839 char *newname, *path, *p;
840 u_int32_t sdid, ddid;
841 int plen, err, retvalue = AFP_OK;
842 u_int16_t svid, dvid;
845 syslog (LOG_INFO, "begin afp_copyfile:");
851 memcpy(&svid, ibuf, sizeof( svid ));
852 ibuf += sizeof( svid );
853 if (( vol = getvolbyvid( svid )) == NULL ) {
854 return( AFPERR_PARAM );
857 memcpy(&sdid, ibuf, sizeof( sdid ));
858 ibuf += sizeof( sdid );
859 if (( dir = dirsearch( vol, sdid )) == NULL ) {
860 return( AFPERR_PARAM );
863 memcpy(&dvid, ibuf, sizeof( dvid ));
864 ibuf += sizeof( dvid );
865 memcpy(&ddid, ibuf, sizeof( ddid ));
866 ibuf += sizeof( ddid );
868 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
869 return( AFPERR_NOOBJ );
871 if ( *path == '\0' ) {
872 return( AFPERR_BADTYPE );
875 /* don't allow copies when the file is open.
876 * XXX: the spec only calls for read/deny write access.
877 * however, copyfile doesn't have any of that info,
878 * and locks need to stay coherent. as a result,
879 * we just balk if the file is opened already. */
880 if (of_findname(vol, curdir, path))
881 return AFPERR_DENYCONF;
883 newname = obj->newtmp;
884 strcpy( newname, path );
886 p = ctoupath( vol, curdir, newname );
888 if (( vol = getvolbyvid( dvid )) == NULL ) {
889 return( AFPERR_PARAM );
892 if (vol->v_flags & AFPVOL_RO)
895 if (( dir = dirsearch( vol, ddid )) == NULL ) {
896 return( AFPERR_PARAM );
899 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
900 return( AFPERR_NOOBJ );
902 if ( *path != '\0' ) {
903 return( AFPERR_BADTYPE );
906 /* one of the handful of places that knows about the path type */
907 if ( *ibuf++ != 2 ) {
908 return( AFPERR_PARAM );
910 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
911 strncpy( newname, ibuf, plen );
912 newname[ plen ] = '\0';
915 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
916 vol_noadouble(vol))) < 0 ) {
920 setvoltime(obj, vol );
923 if (vol->v_flags & AFPVOL_DROPBOX) {
924 retvalue=matchfile2dirperms(newname, vol, sdid);
926 #endif /* DROPKLUDGE */
929 syslog (LOG_INFO, "end afp_copyfile:");
936 static __inline__ int copy_all(const int dfd, const void *buf,
942 syslog(LOG_INFO, "begin copy_all:");
946 if ((cc = write(dfd, buf, buflen)) < 0) {
964 syslog(LOG_INFO, "end copy_all:");
970 /* XXX: this needs to use ad_open and ad_lock. so, we need to
971 * pass in vol and path */
972 int copyfile(src, dst, newname, noadouble )
973 char *src, *dst, *newname;
979 int sfd, dfd, len, err = AFP_OK;
983 syslog(LOG_INFO, "begin copyfile:");
987 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
990 break; /* just copy the data fork */
992 return( AFPERR_ACCESS );
994 return( AFPERR_PARAM );
997 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
998 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1002 return( AFPERR_NOOBJ );
1004 return( AFPERR_ACCESS );
1006 return AFPERR_VLOCK;
1008 return( AFPERR_PARAM );
1013 #ifdef SENDFILE_FLAVOR_LINUX
1014 if (fstat(sfd, &st) == 0) {
1015 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1029 goto copyheader_done;
1031 #endif /* SENDFILE_FLAVOR_LINUX */
1033 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1040 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1048 unlink(ad_path(dst, ADFLAGS_HF));
1054 /* data fork copying */
1055 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1058 return( AFPERR_NOOBJ );
1060 return( AFPERR_ACCESS );
1062 return( AFPERR_PARAM );
1066 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1070 return( AFPERR_NOOBJ );
1072 return( AFPERR_ACCESS );
1074 return AFPERR_VLOCK;
1076 return( AFPERR_PARAM );
1080 #ifdef SENDFILE_FLAVOR_LINUX
1081 if (fstat(sfd, &st) == 0) {
1082 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1095 #endif /* SENDFILE_FLAVOR_LINUX */
1098 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1106 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1115 unlink(ad_path(dst, ADFLAGS_HF));
1121 memset(&ad, 0, sizeof(ad));
1122 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1126 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1128 return( AFPERR_ACCESS );
1130 return AFPERR_VLOCK;
1132 return( AFPERR_PARAM );
1136 len = strlen( newname );
1137 ad_setentrylen( &ad, ADEID_NAME, len );
1138 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1139 ad_flush( &ad, ADFLAGS_HF );
1140 ad_close( &ad, ADFLAGS_HF );
1144 syslog(LOG_INFO, "end copyfile:");
1151 int deletefile( file )
1155 int adflags, err = AFP_OK;
1156 int locktype = ADLOCK_WR;
1157 int openmode = O_RDWR;
1160 syslog(LOG_INFO, "begin deletefile:");
1165 * If can't open read/write then try again read-only. If it's open
1166 * read-only, we must do a read lock instead of a write lock.
1168 /* try to open both at once */
1169 adflags = ADFLAGS_DF|ADFLAGS_HF;
1170 memset(&ad, 0, sizeof(ad));
1171 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1174 adflags = ADFLAGS_DF;
1175 /* that failed. now try to open just the data fork */
1176 memset(&ad, 0, sizeof(ad));
1177 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1180 return AFPERR_NOOBJ;
1182 if(openmode == O_RDWR) {
1183 openmode = O_RDONLY;
1184 locktype = ADLOCK_RD;
1187 return AFPERR_ACCESS;
1190 return AFPERR_VLOCK;
1192 return AFPERR_PARAM;
1198 if(openmode == O_RDWR) {
1199 openmode = O_RDONLY;
1200 locktype = ADLOCK_RD;
1203 return AFPERR_ACCESS;
1206 return AFPERR_VLOCK;
1208 return( AFPERR_PARAM );
1211 break; /* from the while */
1214 if ((adflags & ADFLAGS_HF) &&
1215 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1216 ad_close( &ad, adflags );
1217 return( AFPERR_BUSY );
1220 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1225 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1229 err = AFPERR_ACCESS;
1242 if ( unlink( file ) < 0 ) {
1246 err = AFPERR_ACCESS;
1260 if (adflags & ADFLAGS_HF)
1261 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1262 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1263 ad_close( &ad, adflags );
1266 syslog(LOG_INFO, "end deletefile:");
1274 /* return a file id */
1275 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1278 int ibuflen, *rbuflen;
1290 syslog(LOG_INFO, "begin afp_createid:");
1296 memcpy(&vid, ibuf, sizeof(vid));
1297 ibuf += sizeof(vid);
1299 if (( vol = getvolbyvid( vid )) == NULL ) {
1300 return( AFPERR_PARAM);
1303 if (vol->v_flags & AFPVOL_RO)
1304 return AFPERR_VLOCK;
1306 memcpy(&did, ibuf, sizeof( did ));
1307 ibuf += sizeof(did);
1309 if (( dir = dirsearch( vol, did )) == NULL ) {
1310 return( AFPERR_PARAM );
1313 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1314 return( AFPERR_PARAM );
1317 if ( *path == '\0' ) {
1318 return( AFPERR_BADTYPE );
1321 upath = mtoupath(vol, path);
1322 if (stat(upath, &st) < 0) {
1326 return AFPERR_ACCESS;
1328 return AFPERR_NOOBJ;
1330 return AFPERR_PARAM;
1334 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1335 memcpy(rbuf, &id, sizeof(id));
1336 *rbuflen = sizeof(id);
1337 return AFPERR_EXISTID;
1340 #if AD_VERSION > AD_VERSION1
1341 memset(&ad, 0, sizeof(ad));
1342 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1345 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1346 ad_close(&ad, ADFLAGS_HF);
1349 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1350 memcpy(rbuf, &id, sizeof(id));
1351 *rbuflen = sizeof(id);
1354 #endif /* AD_VERSION > AD_VERSION1 */
1357 syslog(LOG_INFO, "ending afp_createid...:");
1362 return AFPERR_VLOCK;
1366 return AFPERR_ACCESS;
1369 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1370 return AFPERR_PARAM;
1374 /* resolve a file id */
1375 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1378 int ibuflen, *rbuflen;
1386 u_int16_t vid, bitmap;
1389 syslog(LOG_INFO, "begin afp_resolveid:");
1395 memcpy(&vid, ibuf, sizeof(vid));
1396 ibuf += sizeof(vid);
1398 if (( vol = getvolbyvid( vid )) == NULL ) {
1399 return( AFPERR_PARAM);
1402 memcpy(&id, ibuf, sizeof( id ));
1405 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1406 return AFPERR_BADID;
1409 if (( dir = dirsearch( vol, id )) == NULL ) {
1410 return( AFPERR_PARAM );
1413 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1417 return AFPERR_ACCESS;
1421 return AFPERR_PARAM;
1425 /* directories are bad */
1426 if (S_ISDIR(st.st_mode))
1427 return AFPERR_BADTYPE;
1429 memcpy(&bitmap, ibuf, sizeof(bitmap));
1430 bitmap = ntohs( bitmap );
1432 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1433 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1436 *rbuflen = buflen + sizeof(bitmap);
1437 memcpy(rbuf, ibuf, sizeof(bitmap));
1440 syslog(LOG_INFO, "end afp_resolveid:");
1446 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1449 int ibuflen, *rbuflen;
1460 syslog(LOG_INFO, "begin afp_deleteid:");
1466 memcpy(&vid, ibuf, sizeof(vid));
1467 ibuf += sizeof(vid);
1469 if (( vol = getvolbyvid( vid )) == NULL ) {
1470 return( AFPERR_PARAM);
1473 if (vol->v_flags & AFPVOL_RO)
1474 return AFPERR_VLOCK;
1476 memcpy(&id, ibuf, sizeof( id ));
1479 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1483 if (( dir = dirsearch( vol, id )) == NULL ) {
1484 return( AFPERR_PARAM );
1488 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1492 return AFPERR_ACCESS;
1494 /* still try to delete the id */
1498 return AFPERR_PARAM;
1502 /* directories are bad */
1503 if (S_ISDIR(st.st_mode))
1504 return AFPERR_BADTYPE;
1506 if (cnid_delete(vol->v_db, id)) {
1509 return AFPERR_VLOCK;
1512 return AFPERR_ACCESS;
1514 return AFPERR_PARAM;
1519 syslog(LOG_INFO, "end afp_deleteid:");
1524 #endif /* CNID_DB */
1526 #define APPLETEMP ".AppleTempXXXXXX"
1528 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1531 int ibuflen, *rbuflen;
1533 struct stat srcst, destst;
1535 struct dir *dir, *sdir;
1536 char *spath, temp[17], *path, *p;
1537 char *supath, *upath;
1541 #endif /* CNID_DB */
1546 syslog(LOG_INFO, "begin afp_exchangefiles:");
1552 memcpy(&vid, ibuf, sizeof(vid));
1553 ibuf += sizeof(vid);
1555 if (( vol = getvolbyvid( vid )) == NULL ) {
1556 return( AFPERR_PARAM);
1559 if (vol->v_flags & AFPVOL_RO)
1560 return AFPERR_VLOCK;
1562 /* source and destination dids */
1563 memcpy(&sid, ibuf, sizeof(sid));
1564 ibuf += sizeof(sid);
1565 memcpy(&did, ibuf, sizeof(did));
1566 ibuf += sizeof(did);
1569 if ((dir = dirsearch( vol, sid )) == NULL ) {
1570 return( AFPERR_PARAM );
1573 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1574 return( AFPERR_PARAM );
1577 if ( *path == '\0' ) {
1578 return( AFPERR_BADTYPE );
1581 upath = mtoupath(vol, path);
1582 if (stat(upath, &srcst) < 0) {
1588 return AFPERR_ACCESS;
1590 return AFPERR_PARAM;
1594 /* save some stuff */
1596 spath = obj->oldtmp;
1597 supath = obj->newtmp;
1598 strcpy(spath, path);
1599 strcpy(supath, upath); /* this is for the cnid changing */
1600 p = ctoupath( vol, sdir, spath);
1602 /* look for the source cnid. if it doesn't exist, don't worry about
1605 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1606 slen = strlen(supath));
1607 #endif /* CNID_DB */
1609 if (( dir = dirsearch( vol, did )) == NULL ) {
1610 return( AFPERR_PARAM );
1613 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1614 return( AFPERR_PARAM );
1617 if ( *path == '\0' ) {
1618 return( AFPERR_BADTYPE );
1621 /* FPExchangeFiles is the only call that can return the SameObj
1623 if ((curdir == sdir) && strcmp(spath, path) == 0)
1624 return AFPERR_SAMEOBJ;
1626 upath = mtoupath(vol, path);
1627 if (stat(upath, &destst) < 0) {
1633 return AFPERR_ACCESS;
1635 return AFPERR_PARAM;
1640 /* look for destination id. */
1641 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1642 dlen = strlen(upath));
1643 #endif /* CNID_DB */
1645 /* construct a temp name.
1646 * NOTE: the temp file will be in the dest file's directory. it
1647 * will also be inaccessible from AFP. */
1648 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1652 /* now, quickly rename the file. we error if we can't. */
1653 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1654 goto err_exchangefile;
1655 of_rename(vol, sdir, spath, curdir, temp);
1657 /* rename destination to source */
1658 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1659 goto err_src_to_tmp;
1660 of_rename(vol, curdir, path, sdir, spath);
1662 /* rename temp to destination */
1663 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1664 goto err_dest_to_src;
1665 of_rename(vol, curdir, temp, curdir, path);
1668 /* id's need switching. src -> dest and dest -> src. */
1669 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1670 upath, dlen) < 0)) {
1674 err = AFPERR_ACCESS;
1678 goto err_temp_to_dest;
1681 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1682 supath, slen) < 0)) {
1686 err = AFPERR_ACCESS;
1692 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1693 goto err_temp_to_dest;
1695 #endif /* CNID_DB */
1698 syslog(LOG_INFO, "ending afp_exchangefiles:");
1704 /* all this stuff is so that we can unwind a failed operation
1707 /* rename dest to temp */
1708 renamefile(upath, temp, temp, vol_noadouble(vol));
1709 of_rename(vol, curdir, upath, curdir, temp);
1712 /* rename source back to dest */
1713 renamefile(p, upath, path, vol_noadouble(vol));
1714 of_rename(vol, sdir, spath, curdir, path);
1717 /* rename temp back to source */
1718 renamefile(temp, p, spath, vol_noadouble(vol));
1719 of_rename(vol, curdir, temp, sdir, spath);