Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
2b8d4769
Commit
2b8d4769
authored
Apr 17, 2018
by
Dmitry Timoshkov
Committed by
Alexandre Julliard
Apr 17, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
schedsvc: Add support for reading .job files.
Signed-off-by:
Dmitry Timoshkov
<
dmitry@baikal.ru
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
2eb6f886
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
325 additions
and
0 deletions
+325
-0
atsvc.c
dlls/schedsvc/atsvc.c
+301
-0
schedsvc_private.h
dlls/schedsvc/schedsvc_private.h
+1
-0
svc_main.c
dlls/schedsvc/svc_main.c
+9
-0
mstask.idl
include/mstask.idl
+14
-0
No files found.
dlls/schedsvc/atsvc.c
View file @
2b8d4769
...
@@ -22,10 +22,311 @@
...
@@ -22,10 +22,311 @@
#include "windef.h"
#include "windef.h"
#include "atsvc.h"
#include "atsvc.h"
#include "mstask.h"
#include "wine/list.h"
#include "wine/debug.h"
#include "wine/debug.h"
#include "schedsvc_private.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
schedsvc
);
WINE_DEFAULT_DEBUG_CHANNEL
(
schedsvc
);
/* lmat.h defines those, but other types in that file conflict
* with generated atsvc.h typedefs.
*/
#define JOB_ADD_CURRENT_DATE 0x08
#define JOB_NONINTERACTIVE 0x10
typedef
struct
{
USHORT
product_version
;
USHORT
file_version
;
UUID
uuid
;
USHORT
name_size_offset
;
USHORT
trigger_offset
;
USHORT
error_retry_count
;
USHORT
error_retry_interval
;
USHORT
idle_deadline
;
USHORT
idle_wait
;
UINT
priority
;
UINT
maximum_runtime
;
UINT
exit_code
;
UINT
status
;
UINT
flags
;
SYSTEMTIME
last_runtime
;
}
FIXDLEN_DATA
;
struct
job_t
{
struct
list
entry
;
WCHAR
*
name
;
AT_ENUM
info
;
};
static
LONG
current_jobid
=
1
;
static
struct
list
at_job_list
=
LIST_INIT
(
at_job_list
);
static
CRITICAL_SECTION
at_job_list_section
;
static
CRITICAL_SECTION_DEBUG
cs_debug
=
{
0
,
0
,
&
at_job_list_section
,
{
&
cs_debug
.
ProcessLocksList
,
&
cs_debug
.
ProcessLocksList
},
0
,
0
,
{
(
DWORD_PTR
)(
__FILE__
": at_job_list_section"
)
}
};
static
CRITICAL_SECTION
at_job_list_section
=
{
&
cs_debug
,
-
1
,
0
,
0
,
0
,
0
};
static
DWORD
load_unicode_strings
(
const
char
*
data
,
DWORD
limit
,
AT_ENUM
*
info
)
{
DWORD
i
,
data_size
=
0
;
USHORT
len
;
for
(
i
=
0
;
i
<
5
;
i
++
)
{
if
(
limit
<
sizeof
(
USHORT
))
{
TRACE
(
"invalid string %u offset
\n
"
,
i
);
break
;
}
len
=
*
(
USHORT
*
)
data
;
data
+=
sizeof
(
USHORT
);
data_size
+=
sizeof
(
USHORT
);
limit
-=
sizeof
(
USHORT
);
if
(
limit
<
len
*
sizeof
(
WCHAR
))
{
TRACE
(
"invalid string %u size
\n
"
,
i
);
break
;
}
TRACE
(
"string %u: %s
\n
"
,
i
,
wine_dbgstr_wn
((
const
WCHAR
*
)
data
,
len
));
if
(
i
==
0
)
info
->
Command
=
heap_strdupW
((
const
WCHAR
*
)
data
);
data
+=
len
*
sizeof
(
WCHAR
);
data_size
+=
len
*
sizeof
(
WCHAR
);
}
return
data_size
;
}
/* FIXME: read more data, currently only Command is handled */
static
BOOL
load_job_data
(
const
char
*
data
,
DWORD
size
,
AT_ENUM
*
info
)
{
const
FIXDLEN_DATA
*
fixed
;
const
SYSTEMTIME
*
st
;
DWORD
unicode_strings_size
,
data_size
,
triggers_size
;
USHORT
instance_count
,
triggers_count
,
i
;
const
USHORT
*
signature
;
const
TASK_TRIGGER
*
trigger
;
memset
(
info
,
0
,
sizeof
(
*
info
));
if
(
size
<
sizeof
(
*
fixed
))
{
TRACE
(
"no space for FIXDLEN_DATA
\n
"
);
return
FALSE
;
}
fixed
=
(
const
FIXDLEN_DATA
*
)
data
;
TRACE
(
"product_version %04x
\n
"
,
fixed
->
product_version
);
TRACE
(
"file_version %04x
\n
"
,
fixed
->
file_version
);
TRACE
(
"uuid %s
\n
"
,
wine_dbgstr_guid
(
&
fixed
->
uuid
));
TRACE
(
"name_size_offset %04x
\n
"
,
fixed
->
name_size_offset
);
TRACE
(
"trigger_offset %04x
\n
"
,
fixed
->
trigger_offset
);
TRACE
(
"error_retry_count %u
\n
"
,
fixed
->
error_retry_count
);
TRACE
(
"error_retry_interval %u
\n
"
,
fixed
->
error_retry_interval
);
TRACE
(
"idle_deadline %u
\n
"
,
fixed
->
idle_deadline
);
TRACE
(
"idle_wait %u
\n
"
,
fixed
->
idle_wait
);
TRACE
(
"priority %08x
\n
"
,
fixed
->
priority
);
TRACE
(
"maximum_runtime %u
\n
"
,
fixed
->
maximum_runtime
);
TRACE
(
"exit_code %#x
\n
"
,
fixed
->
exit_code
);
TRACE
(
"status %08x
\n
"
,
fixed
->
status
);
TRACE
(
"flags %08x
\n
"
,
fixed
->
flags
);
st
=
&
fixed
->
last_runtime
;
TRACE
(
"last_runtime %d/%d/%d wday %d %d:%d:%d.%03d
\n
"
,
st
->
wDay
,
st
->
wMonth
,
st
->
wYear
,
st
->
wDayOfWeek
,
st
->
wHour
,
st
->
wMinute
,
st
->
wSecond
,
st
->
wMilliseconds
);
/* Instance Count */
if
(
size
<
sizeof
(
*
fixed
)
+
sizeof
(
USHORT
))
{
TRACE
(
"no space for instance count
\n
"
);
return
FALSE
;
}
instance_count
=
*
(
const
USHORT
*
)(
data
+
sizeof
(
*
fixed
));
TRACE
(
"instance count %u
\n
"
,
instance_count
);
if
(
fixed
->
name_size_offset
+
sizeof
(
USHORT
)
<
size
)
unicode_strings_size
=
load_unicode_strings
(
data
+
fixed
->
name_size_offset
,
size
-
fixed
->
name_size_offset
,
info
);
else
{
TRACE
(
"invalid name_size_offset
\n
"
);
return
FALSE
;
}
TRACE
(
"unicode strings end at %#x
\n
"
,
fixed
->
name_size_offset
+
unicode_strings_size
);
if
(
size
<
fixed
->
trigger_offset
+
sizeof
(
USHORT
))
{
TRACE
(
"no space for triggers count
\n
"
);
return
FALSE
;
}
triggers_count
=
*
(
const
USHORT
*
)(
data
+
fixed
->
trigger_offset
);
TRACE
(
"triggers_count %u
\n
"
,
triggers_count
);
triggers_size
=
size
-
fixed
->
trigger_offset
-
sizeof
(
USHORT
);
TRACE
(
"triggers_size %u
\n
"
,
triggers_size
);
trigger
=
(
const
TASK_TRIGGER
*
)(
data
+
fixed
->
trigger_offset
+
sizeof
(
USHORT
));
data
+=
fixed
->
name_size_offset
+
unicode_strings_size
;
size
-=
fixed
->
name_size_offset
+
unicode_strings_size
;
/* User Data */
if
(
size
<
sizeof
(
USHORT
))
{
TRACE
(
"no space for user data size
\n
"
);
return
FALSE
;
}
data_size
=
*
(
const
USHORT
*
)
data
;
if
(
size
<
sizeof
(
USHORT
)
+
data_size
)
{
TRACE
(
"no space for user data
\n
"
);
return
FALSE
;
}
TRACE
(
"User Data size %#x
\n
"
,
data_size
);
size
-=
sizeof
(
USHORT
)
+
data_size
;
data
+=
sizeof
(
USHORT
)
+
data_size
;
/* Reserved Data */
if
(
size
<
sizeof
(
USHORT
))
{
TRACE
(
"no space for reserved data size
\n
"
);
return
FALSE
;
}
data_size
=
*
(
const
USHORT
*
)
data
;
if
(
size
<
sizeof
(
USHORT
)
+
data_size
)
{
TRACE
(
"no space for reserved data
\n
"
);
return
FALSE
;
}
TRACE
(
"Reserved Data size %#x
\n
"
,
data_size
);
size
-=
sizeof
(
USHORT
)
+
data_size
;
data
+=
sizeof
(
USHORT
)
+
data_size
;
/* Trigger Data */
TRACE
(
"trigger_offset %04x, triggers end at %04x
\n
"
,
fixed
->
trigger_offset
,
(
DWORD
)(
fixed
->
trigger_offset
+
sizeof
(
USHORT
)
+
triggers_count
*
sizeof
(
TASK_TRIGGER
)));
triggers_count
=
*
(
const
USHORT
*
)
data
;
TRACE
(
"triggers_count %u
\n
"
,
triggers_count
);
trigger
=
(
const
TASK_TRIGGER
*
)(
data
+
sizeof
(
USHORT
));
if
(
triggers_count
*
sizeof
(
TASK_TRIGGER
)
>
triggers_size
)
{
TRACE
(
"no space for triggers data
\n
"
);
return
FALSE
;
}
for
(
i
=
0
;
i
<
triggers_count
;
i
++
)
{
TRACE
(
"%u: cbTriggerSize = %#x
\n
"
,
i
,
trigger
[
i
].
cbTriggerSize
);
if
(
trigger
[
i
].
cbTriggerSize
!=
sizeof
(
TASK_TRIGGER
))
TRACE
(
"invalid cbTriggerSize
\n
"
);
TRACE
(
"Reserved1 = %#x
\n
"
,
trigger
[
i
].
Reserved1
);
TRACE
(
"wBeginYear = %u
\n
"
,
trigger
->
wBeginYear
);
TRACE
(
"wBeginMonth = %u
\n
"
,
trigger
->
wBeginMonth
);
TRACE
(
"wBeginDay = %u
\n
"
,
trigger
->
wBeginDay
);
TRACE
(
"wEndYear = %u
\n
"
,
trigger
->
wEndYear
);
TRACE
(
"wEndMonth = %u
\n
"
,
trigger
->
wEndMonth
);
TRACE
(
"wEndDay = %u
\n
"
,
trigger
->
wEndDay
);
TRACE
(
"wStartHour = %u
\n
"
,
trigger
->
wStartHour
);
TRACE
(
"wStartMinute = %u
\n
"
,
trigger
->
wStartMinute
);
TRACE
(
"MinutesDuration = %u
\n
"
,
trigger
->
MinutesDuration
);
TRACE
(
"MinutesInterval = %u
\n
"
,
trigger
->
MinutesInterval
);
TRACE
(
"rgFlags = %u
\n
"
,
trigger
->
rgFlags
);
TRACE
(
"TriggerType = %u
\n
"
,
trigger
->
TriggerType
);
TRACE
(
"Reserved2 = %u
\n
"
,
trigger
->
Reserved2
);
TRACE
(
"wRandomMinutesInterval = %u
\n
"
,
trigger
->
wRandomMinutesInterval
);
}
size
-=
sizeof
(
USHORT
)
+
triggers_count
*
sizeof
(
TASK_TRIGGER
);
data
+=
sizeof
(
USHORT
)
+
triggers_count
*
sizeof
(
TASK_TRIGGER
);
if
(
size
<
2
*
sizeof
(
USHORT
)
+
64
)
{
TRACE
(
"no space for signature
\n
"
);
return
TRUE
;
/* signature is optional */
}
signature
=
(
const
USHORT
*
)
data
;
TRACE
(
"signature version %04x, client version %04x
\n
"
,
signature
[
0
],
signature
[
1
]);
return
TRUE
;
}
void
add_job
(
const
WCHAR
*
name
)
{
HANDLE
file
,
mapping
;
DWORD
size
,
try
;
void
*
data
;
struct
job_t
*
job
;
job
=
heap_alloc_zero
(
sizeof
(
*
job
));
if
(
!
job
)
return
;
try
=
1
;
for
(;;)
{
file
=
CreateFileW
(
name
,
GENERIC_READ
,
0
,
NULL
,
OPEN_EXISTING
,
0
,
0
);
if
(
file
==
INVALID_HANDLE_VALUE
)
{
TRACE
(
"Failed to open %s, error %u
\n
"
,
debugstr_w
(
name
),
GetLastError
());
if
(
try
++
>=
3
)
break
;
Sleep
(
100
);
continue
;
}
size
=
GetFileSize
(
file
,
NULL
);
mapping
=
CreateFileMappingW
(
file
,
NULL
,
PAGE_READONLY
,
0
,
0
,
0
);
if
(
!
mapping
)
{
TRACE
(
"Failed to create file mapping %s, error %u
\n
"
,
debugstr_w
(
name
),
GetLastError
());
CloseHandle
(
file
);
break
;
}
data
=
MapViewOfFile
(
mapping
,
FILE_MAP_READ
,
0
,
0
,
0
);
if
(
data
)
{
if
(
load_job_data
(
data
,
size
,
&
job
->
info
))
{
EnterCriticalSection
(
&
at_job_list_section
);
job
->
name
=
heap_strdupW
(
name
);
job
->
info
.
JobId
=
current_jobid
++
;
list_add_tail
(
&
at_job_list
,
&
job
->
entry
);
LeaveCriticalSection
(
&
at_job_list_section
);
}
UnmapViewOfFile
(
data
);
}
CloseHandle
(
mapping
);
CloseHandle
(
file
);
break
;
}
if
(
!
job
->
info
.
JobId
)
{
heap_free
(
job
->
info
.
Command
);
heap_free
(
job
);
}
}
DWORD
__cdecl
NetrJobAdd
(
ATSVC_HANDLE
server_name
,
AT_INFO
*
info
,
DWORD
*
jobid
)
DWORD
__cdecl
NetrJobAdd
(
ATSVC_HANDLE
server_name
,
AT_INFO
*
info
,
DWORD
*
jobid
)
{
{
FIXME
(
"%s,%p,%p: stub
\n
"
,
debugstr_w
(
server_name
),
info
,
jobid
);
FIXME
(
"%s,%p,%p: stub
\n
"
,
debugstr_w
(
server_name
),
info
,
jobid
);
...
...
dlls/schedsvc/schedsvc_private.h
View file @
2b8d4769
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include "wine/unicode.h"
#include "wine/unicode.h"
void
schedsvc_auto_start
(
void
)
DECLSPEC_HIDDEN
;
void
schedsvc_auto_start
(
void
)
DECLSPEC_HIDDEN
;
void
add_job
(
const
WCHAR
*
name
)
DECLSPEC_HIDDEN
;
static
inline
WCHAR
*
heap_strdupW
(
const
WCHAR
*
src
)
static
inline
WCHAR
*
heap_strdupW
(
const
WCHAR
*
src
)
{
{
...
...
dlls/schedsvc/svc_main.c
View file @
2b8d4769
...
@@ -82,6 +82,15 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
...
@@ -82,6 +82,15 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
switch
(
info
.
data
.
Action
)
switch
(
info
.
data
.
Action
)
{
{
case
FILE_ACTION_ADDED
:
TRACE
(
"FILE_ACTION_ADDED %s
\n
"
,
debugstr_w
(
info
.
data
.
FileName
));
GetWindowsDirectoryW
(
path
,
MAX_PATH
);
lstrcatW
(
path
,
tasksW
);
lstrcatW
(
path
,
info
.
data
.
FileName
);
add_job
(
path
);
break
;
default:
default:
FIXME
(
"%s: action %#x not handled
\n
"
,
debugstr_w
(
info
.
data
.
FileName
),
info
.
data
.
Action
);
FIXME
(
"%s: action %#x not handled
\n
"
,
debugstr_w
(
info
.
data
.
FileName
),
info
.
data
.
Action
);
break
;
break
;
...
...
include/mstask.idl
View file @
2b8d4769
...
@@ -55,6 +55,20 @@ cpp_quote("#define TASK_OCTOBER 0x200")
...
@@ -55,6 +55,20 @@ cpp_quote("#define TASK_OCTOBER 0x200")
cpp_quote
(
"#define TASK_NOVEMBER 0x400"
)
cpp_quote
(
"#define TASK_NOVEMBER 0x400"
)
cpp_quote
(
"#define TASK_DECEMBER 0x800"
)
cpp_quote
(
"#define TASK_DECEMBER 0x800"
)
cpp_quote
(
"#define TASK_FLAG_INTERACTIVE 0x0001"
)
cpp_quote
(
"#define TASK_FLAG_DELETE_WHEN_DONE 0x0002"
)
cpp_quote
(
"#define TASK_FLAG_DISABLED 0x0004"
)
cpp_quote
(
"#define TASK_FLAG_START_ONLY_IF_IDLE 0x0010"
)
cpp_quote
(
"#define TASK_FLAG_KILL_ON_IDLE_END 0x0020"
)
cpp_quote
(
"#define TASK_FLAG_DONT_START_IF_ON_BATTERIES 0x0040"
)
cpp_quote
(
"#define TASK_FLAG_KILL_IF_GOING_ON_BATTERIES 0x0080"
)
cpp_quote
(
"#define TASK_FLAG_RUN_ONLY_IF_DOCKED 0x0100"
)
cpp_quote
(
"#define TASK_FLAG_HIDDEN 0x0200"
)
cpp_quote
(
"#define TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET 0x0400"
)
cpp_quote
(
"#define TASK_FLAG_RESTART_ON_IDLE_RESUME 0x0800"
)
cpp_quote
(
"#define TASK_FLAG_SYSTEM_REQUIRED 0x1000"
)
cpp_quote
(
"#define TASK_FLAG_RUN_ONLY_IF_LOGGED_ON 0x2000"
)
cpp_quote
(
"#define TASK_TRIGGER_FLAG_HAS_END_DATE 0x1"
)
cpp_quote
(
"#define TASK_TRIGGER_FLAG_HAS_END_DATE 0x1"
)
cpp_quote
(
"#define TASK_TRIGGER_FLAG_KILL_AT_DURATION_END 0x2"
)
cpp_quote
(
"#define TASK_TRIGGER_FLAG_KILL_AT_DURATION_END 0x2"
)
cpp_quote
(
"#define TASK_TRIGGER_FLAG_DISABLED 0x4"
)
cpp_quote
(
"#define TASK_TRIGGER_FLAG_DISABLED 0x4"
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment