#define INCL_LONGLONG #define INCL_DOS #define INCL_DOSERRORS //_SMB_H #include #include #include #include #include #ifndef TESTING #define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) #include "local.h" #include "xfile.h" #include "pstring.h" #include "debug.h" #else #define DEBUG(a,b) (0) #endif #include #ifndef ENOATTR #define ENOATTR 22 #endif static void maperrno(int rc) { switch (rc) { case ERROR_PATH_NOT_FOUND : case ERROR_FILE_NOT_FOUND : errno = ENOENT; break; case ERROR_INVALID_HANDLE : errno = EBADF; break; case ERROR_ACCESS_DENIED : errno = EACCES; break; case ERROR_BUFFER_OVERFLOW : case ERROR_NOT_ENOUGH_MEMORY : errno = ERANGE; break; case ERROR_INVALID_EA_NAME : errno = ENOATTR; break; case ERROR_INVALID_LEVEL : case ERROR_INVALID_PARAMETER : errno = EINVAL; break; case ERROR_SHARING_VIOLATION : errno = EACCES; break; default : errno = EINVAL; } } static ssize_t unigetxattr (const char *path, int file, const char *name, void *value, size_t size) { int rc, namelen; EAOP2 eaop2 = {0}; PGEA2LIST pgea2list = NULL; PFEA2LIST pfea2list = NULL; char * p; if ((!path && !file) || !name) { errno = EINVAL; return -1; } namelen = strlen(name); if (namelen > 0xFF) { errno = EINVAL; return -1; } pgea2list = (PGEA2LIST)calloc(sizeof(GEA2LIST) + namelen + 1, 1); pgea2list->list[0].oNextEntryOffset = 0; pgea2list->list[0].cbName = namelen; strcpy(pgea2list->list[0].szName, name); pgea2list->cbList = sizeof(GEA2LIST) + namelen; // max ea is 64kb pfea2list = (PFEA2LIST)calloc(sizeof(FEA2LIST) + 0x10000, 1); pfea2list->cbList = sizeof(FEA2LIST) + 0x10000; eaop2.fpGEA2List = pgea2list; eaop2.fpFEA2List = pfea2list; eaop2.oError = 0; do { if (path) { char npath[CCHMAXPATH + 1] = {0}; strncpy(npath, path, CCHMAXPATH); for (p = npath; *p; p++) { if (*p == '/') *p = '\\'; } rc = DosQueryPathInfo(npath, FIL_QUERYEASFROMLIST, &eaop2, sizeof(eaop2)); } else { rc = DosQueryFileInfo( file, FIL_QUERYEASFROMLIST, &eaop2, sizeof(eaop2)); } if (rc) { maperrno(rc); rc = -1; break; } if (strnicmp(pfea2list->list[0].szName, name, namelen) || pfea2list->list[0].cbValue == 0) { errno = ENOATTR; rc = -1; break; } rc = pfea2list->list[0].cbValue; if (value) { if (size < rc) { errno = ERANGE; rc = -1; } else { p = pfea2list->list[0].szName + pfea2list->list[0].cbName + 1; memcpy(value, p, rc); } } } while (0); if (pgea2list) { free(pgea2list); } if (pgea2list) { free(pfea2list); } DEBUG(4,("unigetxattr : (%s:%d) %s %d\n", path ? path : "null", file, name, rc)); return rc; } ssize_t getxattr (const char *path, const char *name, void *value, size_t size) { return unigetxattr(path, 0, name, value, size); } ssize_t lgetxattr (const char *path, const char *name, void *value, size_t size) { return unigetxattr(path, 0, name, value, size); } ssize_t fgetxattr (int filedes, const char *name, void *value, size_t size) { return unigetxattr(0, filedes, name, value, size); } static ssize_t unilistxattr (const char *path, int file, char *list, size_t size) { ssize_t gotsize = 0; unsigned long ulCount = -1; int rc; char * buf, *p = list; PFEA2 pfea; FILESTATUS4 stat = {0}; char npath[CCHMAXPATH + 1] = {0}; if (!path && !file) { errno = EINVAL; return -1; } if (path) { char * p; strncpy(npath, path, CCHMAXPATH); for (p = npath; *p; p++) { if (*p == '/') *p = '\\'; } rc = DosQueryPathInfo(npath, FIL_QUERYEASIZE, &stat, sizeof(stat)); } else { rc = DosQueryFileInfo( file, FIL_QUERYEASIZE, &stat, sizeof(stat)); } if (rc) { DEBUG(4,("unilistxattr1 : (%s:%d) %d\n", path ? path : "null", file, rc)); maperrno(rc); return -1; } if (stat.cbList <= 4) { // NO ea return 0; } buf = (char *)malloc(stat.cbList * 2); rc = DosEnumAttribute(path ? 1 : 0, path ? (PVOID)path : (PVOID)&file, 1, (PVOID)buf, stat.cbList * 2, &ulCount, 1); if (rc) { DEBUG(4,("unilistxattr2 : (%s:%d) %d\n", path ? path : "null", file, rc)); maperrno(rc); free(buf); return -1; } if (ulCount > 0) for (pfea = (PFEA2)buf;;pfea = (PFEA2)((char *)pfea + pfea->oNextEntryOffset)) { if (pfea->cbName > 0) { gotsize += pfea->cbName + 1; if (p && size >= gotsize) { pfea->szName[pfea->cbName] = 0; strcpy(p, pfea->szName); p += strlen(p) + 1; } } if (!pfea->oNextEntryOffset) { break; } } free(buf); DEBUG(4,("unilistxattr : (%s:%d) %d\n", path ? path : "null", file, gotsize)); if (gotsize > size) { errno = ERANGE; return list ? -1 : gotsize; } return gotsize; } ssize_t listxattr (const char *path, char *list, size_t size) { return unilistxattr(path, 0, list, size); } ssize_t llistxattr (const char *path, char *list, size_t size) { return unilistxattr(path, 0, list, size); } ssize_t flistxattr (int file, char *list, size_t size) { return unilistxattr(0, file, list, size); } static int uniremovexattr (const char *path, int file, const char *name) { int rc, namelen; EAOP2 eaop2 = {0}; PFEA2LIST pfea2list = NULL; char buf[300] = {0}; if ((!path && !file) || !name) { errno = EINVAL; return -1; } namelen = strlen(name); if (namelen > 0xFF) { errno = EINVAL; return -1; } pfea2list = (PFEA2LIST)buf; pfea2list->list[0].cbName = namelen; pfea2list->list[0].cbValue = 0; pfea2list->list[0].fEA = 0; strcpy(pfea2list->list[0].szName, name); pfea2list->cbList = sizeof(FEA2LIST) + namelen; eaop2.fpFEA2List = pfea2list; if (path) { char npath[CCHMAXPATH + 1] = {0}; char * p; strncpy(npath, path, CCHMAXPATH); for (p = npath; *p; p++) { if (*p == '/') *p = '\\'; } rc = DosSetPathInfo(npath, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2), DSPI_WRTTHRU); } else { rc = DosSetFileInfo( file, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2)); } if (rc) { maperrno(rc); return -1; } return 0; } int removexattr (const char *path, const char *name) { return uniremovexattr (path, 0, name); } int lremovexattr (const char *path, const char *name) { return uniremovexattr (path, 0, name); } int fremovexattr (int file, const char *name) { return uniremovexattr (0, file, name); } #ifndef XATTR_CREATE #define XATTR_CREATE 1 #endif #ifndef XATTR_REPLACE #define XATTR_REPLACE 2 #endif static int unisetxattr (const char *path, int file, const char *name, const void *value, size_t size, int flags) { int rc, namelen, totalsize; EAOP2 eaop2 = {0}; PFEA2LIST pfea2list = NULL; char * p; if ((!path && !file) || !name || (!value && size)) { errno = EINVAL; return -1; } namelen = strlen(name); if (namelen > 0xFF) { errno = EINVAL; return -1; } if (flags & (XATTR_CREATE | XATTR_REPLACE)) { ssize_t esize = unigetxattr(path, file, name, 0, 0); if (flags & XATTR_CREATE && esize > 0) { errno = EEXIST; return -1; } if (flags & XATTR_REPLACE && esize < 0) { errno = ENOATTR; return -1; } } totalsize = sizeof(GEALIST) + size + namelen + 1; pfea2list = (PFEA2LIST)calloc(totalsize, 1); pfea2list->cbList = totalsize; pfea2list->list[0].oNextEntryOffset = 0; pfea2list->list[0].cbName = namelen; pfea2list->list[0].cbValue = size; strcpy(pfea2list->list[0].szName, name); if (value) { memcpy(pfea2list->list[0].szName + namelen + 1, value, size); } eaop2.fpFEA2List = pfea2list; if (path) { char npath[CCHMAXPATH + 1] = {0}; char * p; strncpy(npath, path, CCHMAXPATH); for (p = npath; *p; p++) { if (*p == '/') *p = '\\'; } rc = DosSetPathInfo(npath, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2), DSPI_WRTTHRU); } else { rc = DosSetFileInfo( file, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2)); } free(pfea2list); if (rc) { maperrno(rc); return -1; } return 0; } int setxattr (const char *path, const char *name, const void *value, size_t size, int flags) { return unisetxattr (path, 0, name, value, size, flags); } int lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags) { return unisetxattr (path, 0, name, value, size, flags); } int fsetxattr (int file, const char *name, const void *value, size_t size, int flags) { return unisetxattr (0, file, name, value, size, flags); } #ifdef TESTING #include #include int main(int argc, char ** argv) { int rc; if (argc < 2) { char * p = strrchr(*argv, '\\'); p = p ? p + 1 : *argv; printf("Usage: %s [ ...]\n", p); return 1; } for (argc--, argv++; argc > 0; argc--, argv++) { char * ealist, * p; ssize_t ealistsize; printf("Processing file <%s>\n", *argv); ealistsize = listxattr(*argv, 0, 0); printf("EA list size %ld\n", ealistsize); /* if (ealistsize) { continue; } */ ealist = malloc(ealistsize); ealistsize = listxattr(*argv, ealist, ealistsize); printf("EA list size2 %ld\n", ealistsize); if (ealistsize > 0) { int file = open(*argv, O_RDWR | O_BINARY, S_IREAD | S_IWRITE); if (file < 0) { printf("Cant open file <%s> : %d\n", *argv, errno); continue; } for (p = ealist; (p - ealist) < ealistsize && *p; p += strlen(p) + 1) { ssize_t easize; unsigned char * eavalue; printf("EA name <%s>\n", p); easize = fgetxattr(file, p, 0, 0); printf("EA size %ld\n", easize); eavalue = malloc(easize); easize = fgetxattr(file, p, eavalue, easize); printf("EA size2 %ld\n", easize); /* if (easize > 0) { unsigned char * q; printf("Eavalue :"); for (q = eavalue; q - eavalue < easize; q++) { printf(" %02x", *q); } printf("\n"); } */ free(eavalue); } rc = fremovexattr(file, ealist); printf("remove <%s> rc %d\n", ealist, rc); rc = fsetxattr(file, "XYZ3", "QWERTY", 6, 0); printf("set rc %d\n", rc); /* rc = fsetxattr(file, "XYZ3", "QWERTY", 6, XATTR_REPLACE); printf("set rc %d\n", rc); */ free(ealist); close(file); } } return 0; } #endif