source: branches/samba-3.5.x/source3/lib/os2helper.c@ 1075

Last change on this file since 1075 was 850, checked in by Silvan Scherrer, 11 years ago

Samba Server 3.5: fix EA problem

File size: 13.1 KB
Line 
1/* This file contains Samba helper functions for eComStation (OS/2) -
2 * do not try to compile on other platforms!
3 *
4 * Copyright (C) 2007-2011
5 * Silvan Scherrer
6 * Yuri Dario
7 * Paul Smedley
8 * Herwig Bauernfeind
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24#ifdef __OS2__
25
26#define INCL_LONGLONG
27#define INCL_DOS
28#define INCL_DOSPROCESS
29#define INCL_DOSPROFILE
30#define INCL_DOSMISC
31#define INCL_DOSMODULEMGR
32#define INCL_DOSDATETIME
33#define INCL_DOSERRORS
34
35#include <os2.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <errno.h>
39#include <time.h>
40#include <types.h>
41#include <string.h>
42#include <sys/socket.h>
43#include <malloc.h>
44
45/* these define the attribute byte as seen by DOS */
46#define aRONLY (1L<<0) /* 0x01 */
47#define aHIDDEN (1L<<1) /* 0x02 */
48#define aSYSTEM (1L<<2) /* 0x04 */
49#define aVOLID (1L<<3) /* 0x08 */
50#define aDIR (1L<<4) /* 0x10 */
51#define aARCH (1L<<5) /* 0x20 */
52
53// Samba DEBUG() needs the following includes and defines
54#include <stdbool.h>
55#include "../lib/replace/replace.h"
56#include "local.h"
57#include "../lib/util/attr.h"
58#include "../lib/util/xfile.h"
59#include "debug.h"
60
61#ifndef ENOATTR
62#define ENOATTR 22
63#endif
64
65int os2_ftruncate(int fd, off_t size)
66{
67 /* We call __libc_Back_ioFileSizeSet directly instead of
68 ftruncate to force it not to zero expanding files to
69 optimize Samba performance when copying files */
70
71 int rc = __libc_Back_ioFileSizeSet(fd, size, 0);
72 if (rc < 0)
73 {
74 errno = -rc;
75 return -1;
76 }
77 return 0;
78}
79
80int os2_isattribute(char *path, unsigned short attr)
81{
82 HDIR hdirFindHandle = HDIR_CREATE;
83 FILEFINDBUF3 FindBuffer = {0}; /* Returned from FindFirst/Next */
84 USHORT dosattr; /* attribute to search for */
85 ULONG ulResultBufLen = sizeof(FILEFINDBUF3);
86 ULONG ulFindCount = 1; /* Look for 1 file at a time */
87 APIRET rc = NO_ERROR; /* Return code */
88 if (attr == aARCH)
89 dosattr=MUST_HAVE_ARCHIVED;
90 else if (attr == aRONLY)
91 dosattr=MUST_HAVE_READONLY;
92 else if (attr == aSYSTEM)
93 dosattr=MUST_HAVE_SYSTEM;
94 else if (attr == aHIDDEN)
95 dosattr=MUST_HAVE_HIDDEN;
96
97 rc = DosFindFirst( path, /* File pattern - all files */
98 &hdirFindHandle, /* Directory search handle */
99 dosattr,
100 &FindBuffer, /* Result buffer */
101 ulResultBufLen, /* Result buffer length */
102 &ulFindCount, /* Number of entries to find */
103 FIL_STANDARD); /* Return Level 1 file info */
104
105 if (rc != NO_ERROR) {
106 rc = DosFindClose(hdirFindHandle); /* Close our directory handle */
107 return 1;
108 } else {
109 rc = DosFindClose(hdirFindHandle); /* Close our directory handle */
110 return 0;
111 } /* endif */
112}
113
114// get the exe name (including path)
115bool os2_GetExeName(char *sExeName, int lExeName)
116{
117 APIRET rc = NO_ERROR;
118 PPIB ppib = NULL;
119
120 // we search for the infoblock to get the module name
121 rc = DosGetInfoBlocks(NULL, &ppib);
122 if (rc != NO_ERROR)
123 {
124 return false;
125 }
126
127 // with the module name we get the path (including the exe name)
128 rc = DosQueryModuleName(ppib->pib_hmte, lExeName, sExeName);
129 if (rc != NO_ERROR)
130 {
131 return false;
132 }
133 return true;
134}
135
136// we search the path of the .exe and return it
137int os2_GetExePath(char *buff)
138{
139 char sExeName [_MAX_PATH];
140 char sDrive [_MAX_PATH], sDir [_MAX_DIR];
141
142 if (!os2_GetExeName(sExeName, sizeof(sExeName)))
143 return false;
144
145 // we split to the different values
146 _splitpath(sExeName, sDrive, sDir, NULL, NULL);
147 // strcat(sDrive, sDir);
148 strncat(sDrive, sDir, strlen(sDir) -1);
149 strcpy(buff, sDrive);
150
151 return true;
152}
153
154/* OS/2 specific pipe implementation, we have to use socketpair as select on
155 filehandle is not working. */
156int os2_pipe(int fds[2])
157{
158 int rc = 0;
159
160 rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
161 return rc;
162}
163
164/* OS/2-specific random functions. these functions used to be based on APR
165 random code, but we discovered some nasty problems with it on fast hardware
166 (especially on quadcore) and decided to rewrite it with libc random() */
167void os2_randget(char * buffer, int length)
168{
169 UCHAR randbyte();
170 unsigned int idx;
171
172 for (idx=0; idx<length; idx++)
173 buffer[idx] = randbyte();
174
175}
176
177UCHAR randbyte()
178{
179 int c;
180 UCHAR byte;
181 ULONG ulrandom;
182 ulrandom = random();
183
184 for (c = 0; c < sizeof(ulrandom); c++) {
185 byte ^= ((UCHAR *)&ulrandom)[c];
186 }
187
188 return byte;
189}
190
191
192void maperrno(int rc)
193{
194 switch (rc)
195 {
196 case ERROR_PATH_NOT_FOUND :
197 case ERROR_FILE_NOT_FOUND : errno = ENOENT; break;
198 case ERROR_INVALID_HANDLE : errno = EBADF; break;
199 case ERROR_ACCESS_DENIED : errno = EACCES; break;
200 case ERROR_BUFFER_OVERFLOW :
201 case ERROR_NOT_ENOUGH_MEMORY : errno = ERANGE; break;
202 case ERROR_INVALID_EA_NAME : errno = ENOATTR; break;
203 case ERROR_INVALID_LEVEL :
204 case ERROR_INVALID_PARAMETER : errno = EINVAL; break;
205 case ERROR_SHARING_VIOLATION : errno = EACCES; break;
206 default : errno = EINVAL;
207 }
208}
209
210ssize_t unigetxattr (const char *path, int file, const char *name, void *value, size_t size)
211{
212 int rc, namelen;
213 EAOP2 eaop2 = {0};
214 PGEA2LIST pgea2list = NULL;
215 PFEA2LIST pfea2list = NULL;
216 char * p;
217
218 if ((!path && !file) || !name)
219 {
220 errno = EINVAL;
221 return -1;
222 }
223 namelen = strlen(name);
224 if (namelen > 0xFF)
225 {
226 errno = EINVAL;
227 return -1;
228 }
229 pgea2list = (PGEA2LIST)calloc(sizeof(GEA2LIST) + namelen + 1, 1);
230 pgea2list->list[0].oNextEntryOffset = 0;
231 pgea2list->list[0].cbName = namelen;
232 strcpy(pgea2list->list[0].szName, name);
233 pgea2list->cbList = sizeof(GEA2LIST) + namelen;
234
235 // max ea is 64kb
236 pfea2list = (PFEA2LIST)calloc(sizeof(FEA2LIST) + 0x10000, 1);
237 pfea2list->cbList = sizeof(FEA2LIST) + 0x10000;
238
239 eaop2.fpGEA2List = pgea2list;
240 eaop2.fpFEA2List = pfea2list;
241 eaop2.oError = 0;
242 do
243 {
244 if (path)
245 {
246 char npath[CCHMAXPATH + 1] = {0};
247 strncpy(npath, path, CCHMAXPATH);
248 for (p = npath; *p; p++)
249 {
250 if (*p == '/') *p = '\\';
251 }
252 rc = DosQueryPathInfo(npath, FIL_QUERYEASFROMLIST, &eaop2, sizeof(eaop2));
253 }
254 else
255 {
256 rc = DosQueryFileInfo( file, FIL_QUERYEASFROMLIST, &eaop2, sizeof(eaop2));
257 }
258 if (rc)
259 {
260 maperrno(rc);
261 rc = -1;
262 break;
263 }
264 if (strnicmp(pfea2list->list[0].szName, name, namelen) || pfea2list->list[0].cbValue == 0)
265 {
266 errno = ENOATTR;
267 rc = -1;
268 break;
269 }
270 rc = pfea2list->list[0].cbValue;
271 if (value)
272 {
273 if (size < rc)
274 {
275 errno = ERANGE;
276 rc = -1;
277 }
278 else
279 {
280 p = pfea2list->list[0].szName + pfea2list->list[0].cbName + 1;
281 memcpy(value, p, rc);
282 }
283 }
284 } while (0);
285 if (pgea2list)
286 {
287 free(pgea2list);
288 }
289 if (pfea2list)
290 {
291 free(pfea2list);
292 }
293
294 DEBUG(5,("unigetxattr : (%s:%d) %s %d\n", path ? path : "null", file, name, rc));
295
296 return rc;
297}
298
299ssize_t unilistxattr (const char *path, int file, char *list, size_t size)
300{
301 ssize_t gotsize = 0;
302 unsigned long ulCount = -1;
303 int rc;
304 char * buf, *p = list;
305 PFEA2 pfea;
306 FILESTATUS4 stat = {0};
307 char npath[CCHMAXPATH + 1] = {0};
308 if (!path && !file)
309 {
310 errno = EINVAL;
311 return -1;
312 }
313 if (path)
314 {
315 char * p;
316 strncpy(npath, path, CCHMAXPATH);
317 for (p = npath; *p; p++)
318 {
319 if (*p == '/') *p = '\\';
320 }
321 rc = DosQueryPathInfo(npath, FIL_QUERYEASIZE, &stat, sizeof(stat));
322 }
323 else
324 {
325 rc = DosQueryFileInfo( file, FIL_QUERYEASIZE, &stat, sizeof(stat));
326 }
327 if (rc)
328 {
329 DEBUG(4,("unilistxattr1 : (%s:%d) %d\n", path ? npath : "null", file, rc));
330 maperrno(rc);
331 return -1;
332 }
333 if (stat.cbList <= 4)
334 {
335 // NO ea
336 return 0;
337 }
338 //YD DosEnumAttribute doesn't like high-mem buffers, get a low one.
339 buf = (char *)_tmalloc(stat.cbList * 2);
340 rc = DosEnumAttribute(path ? 1 : 0, path ? (PVOID)npath : (PVOID)&file, 1, (PVOID)buf, stat.cbList * 2, &ulCount, 1);
341 if (rc)
342 {
343 DEBUG(4,("unilistxattr2 : (%s:%d) %d\n", path ? npath : "null", file, rc));
344 maperrno(rc);
345 _tfree(buf);
346 return -1;
347 }
348 if (ulCount > 0)
349 for (pfea = (PFEA2)buf;;pfea = (PFEA2)((char *)pfea + pfea->oNextEntryOffset))
350 {
351 if (pfea->cbName > 0)
352 {
353 gotsize += pfea->cbName + 1;
354 if (p && size >= gotsize)
355 {
356 pfea->szName[pfea->cbName] = 0;
357 strcpy(p, pfea->szName);
358 p += strlen(p) + 1;
359 }
360 }
361 // had to be added to avoid crash in case of broken extended attributes
362 if (pfea->oNextEntryOffset > 0x10000)
363 {
364 DEBUG(4, ("Broken Extended Attributes detected for: %s:%d, Last EA:%s\n", path ? path : "null", file, pfea->szName));
365 break;
366 }
367 if (!pfea->oNextEntryOffset)
368 {
369 break;
370 }
371 }
372 _tfree(buf);
373
374 DEBUG(5,("unilistxattr : (%s:%d) %d\n", path ? path : "null", file, gotsize));
375
376 if (gotsize > size)
377 {
378 errno = ERANGE;
379 return list ? -1 : gotsize;
380 }
381 return gotsize;
382}
383
384int uniremovexattr (const char *path, int file, const char *name)
385{
386 int rc, namelen;
387 EAOP2 eaop2 = {0};
388 PFEA2LIST pfea2list = NULL;
389 char buf[300] = {0};
390
391 if ((!path && !file) || !name)
392 {
393 errno = EINVAL;
394 return -1;
395 }
396
397 namelen = strlen(name);
398 if (namelen > 0xFF)
399 {
400 errno = EINVAL;
401 return -1;
402 }
403
404 pfea2list = (PFEA2LIST)buf;
405 pfea2list->list[0].cbName = namelen;
406 pfea2list->list[0].cbValue = 0;
407 pfea2list->list[0].fEA = 0;
408 strcpy(pfea2list->list[0].szName, name);
409 pfea2list->cbList = sizeof(FEA2LIST) + namelen;
410 eaop2.fpFEA2List = pfea2list;
411
412 if (path)
413 {
414 char npath[CCHMAXPATH + 1] = {0};
415 char * p;
416 strncpy(npath, path, CCHMAXPATH);
417 for (p = npath; *p; p++)
418 {
419 if (*p == '/') *p = '\\';
420 }
421 rc = DosSetPathInfo(npath, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2), DSPI_WRTTHRU);
422 }
423 else
424 {
425 rc = DosSetFileInfo( file, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2));
426 }
427 if (rc)
428 {
429 maperrno(rc);
430 return -1;
431 }
432 return 0;
433}
434
435#ifndef XATTR_CREATE
436#define XATTR_CREATE 1
437#endif
438#ifndef XATTR_REPLACE
439#define XATTR_REPLACE 2
440#endif
441
442int unisetxattr (const char *path, int file, const char *name, const void *value, size_t size, int flags)
443{
444 int rc, namelen, totalsize;
445 EAOP2 eaop2 = {0};
446 PFEA2LIST pfea2list = NULL;
447 char * p;
448
449 DEBUG(5,("unisetxattr : (%s:%d) %s %d\n", path ? path : "null", file, name, size));
450
451 if ((!path && !file) || !name || (!value && size))
452 {
453 errno = EINVAL;
454 return -1;
455 }
456 namelen = strlen(name);
457 if (namelen > 0xFF)
458 {
459 errno = EINVAL;
460 return -1;
461 }
462
463 if (flags & (XATTR_CREATE | XATTR_REPLACE))
464 {
465 ssize_t esize = unigetxattr(path, file, name, 0, 0);
466 if (flags & XATTR_CREATE && esize > 0)
467 {
468 errno = EEXIST;
469 return -1;
470 }
471 if (flags & XATTR_REPLACE && esize < 0)
472 {
473 errno = ENOATTR;
474 return -1;
475 }
476 }
477
478 totalsize = sizeof(FEA2LIST) + size + namelen + 1;
479
480 pfea2list = (PFEA2LIST)calloc(totalsize, 1);
481 pfea2list->cbList = totalsize;
482 pfea2list->list[0].oNextEntryOffset = 0;
483 pfea2list->list[0].cbName = namelen;
484 pfea2list->list[0].cbValue = size;
485 strcpy(pfea2list->list[0].szName, name);
486 if (value)
487 {
488 memcpy(pfea2list->list[0].szName + namelen + 1, value, size);
489 }
490 eaop2.fpFEA2List = pfea2list;
491
492 if (path)
493 {
494 char npath[CCHMAXPATH + 1] = {0};
495 char * p;
496 strncpy(npath, path, CCHMAXPATH);
497 for (p = npath; *p; p++)
498 {
499 if (*p == '/') *p = '\\';
500 }
501 rc = DosSetPathInfo(npath, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2), DSPI_WRTTHRU);
502 }
503 else
504 {
505 rc = DosSetFileInfo( file, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2));
506 }
507 free(pfea2list);
508 if (rc)
509 {
510 maperrno(rc);
511 return -1;
512 }
513 return 0;
514}
515
516/* set date/time on OS/2 */
517int os2_setdatetime(time_t t)
518{
519 struct tm *tm;
520
521 tm = localtime(&t);
522 if (!tm) {
523 return -1;
524 }
525
526 DATETIME DateTime = {0};
527 APIRET rc = NO_ERROR;
528
529 /* Get current date/time to properly fill structure */
530 rc = DosGetDateTime(&DateTime);
531 if (rc != NO_ERROR) {
532 return rc;
533 }
534
535 DateTime.year = (USHORT) ((BYTE) tm->tm_year+1900);
536 DateTime.month = (UCHAR) ((BYTE) tm->tm_mon+1);
537 DateTime.day = (UCHAR) ((BYTE) tm->tm_mday);
538 DateTime.hours = (UCHAR) ((BYTE) tm->tm_hour);
539 DateTime.minutes = (UCHAR) ((BYTE) tm->tm_min);
540 DateTime.seconds = (UCHAR) ((BYTE) tm->tm_sec);
541
542 rc = DosSetDateTime(&DateTime); /* Update the date and time */
543
544 if (rc!= NO_ERROR) {
545 printf ("DosSetDateTime error : return code = %u\n", rc);
546 }
547 return rc;
548}
549
550#endif
Note: See TracBrowser for help on using the repository browser.